diff --git a/src/main/java/cz/cvut/kbss/termit/event/VocabularyCreatedEvent.java b/src/main/java/cz/cvut/kbss/termit/event/VocabularyCreatedEvent.java new file mode 100644 index 000000000..b4cf649a8 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/event/VocabularyCreatedEvent.java @@ -0,0 +1,13 @@ +package cz.cvut.kbss.termit.event; + +import org.springframework.context.ApplicationEvent; + +/** + * Indicates that a vocabulary has been created. + */ +public class VocabularyCreatedEvent extends ApplicationEvent { + + public VocabularyCreatedEvent(Object source) { + super(source); + } +} diff --git a/src/main/java/cz/cvut/kbss/termit/exception/AmbiguousVocabularyContextException.java b/src/main/java/cz/cvut/kbss/termit/exception/AmbiguousVocabularyContextException.java new file mode 100644 index 000000000..fa8fbb333 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/exception/AmbiguousVocabularyContextException.java @@ -0,0 +1,12 @@ +package cz.cvut.kbss.termit.exception; + +/** + * Indicates that a vocabulary has been found in multiple repository contexts, and it was not possible to determine + * which one to use. + */ +public class AmbiguousVocabularyContextException extends TermItException { + + public AmbiguousVocabularyContextException(String message) { + super(message); + } +} diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/context/CachingVocabularyContextMapper.java b/src/main/java/cz/cvut/kbss/termit/persistence/context/CachingVocabularyContextMapper.java new file mode 100644 index 000000000..cb233f2cb --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/persistence/context/CachingVocabularyContextMapper.java @@ -0,0 +1,78 @@ +package cz.cvut.kbss.termit.persistence.context; + +import cz.cvut.kbss.jopa.model.EntityManager; +import cz.cvut.kbss.termit.event.EvictCacheEvent; +import cz.cvut.kbss.termit.event.VocabularyCreatedEvent; +import cz.cvut.kbss.termit.exception.AmbiguousVocabularyContextException; +import cz.cvut.kbss.termit.util.Vocabulary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cz.cvut.kbss.termit.util.Utils.uriToString; + +/** + * Caching implementation of the {@link VocabularyContextMapper}. + *

+ * Context map is loaded on startup and reloaded every time a vocabulary is created. + */ +@Component +@Profile("!no-cache") +public class CachingVocabularyContextMapper implements VocabularyContextMapper { + + private static final Logger LOG = LoggerFactory.getLogger(CachingVocabularyContextMapper.class); + + private final EntityManager em; + + private Map> contexts; + + public CachingVocabularyContextMapper(EntityManager em) { + this.em = em; + } + + /** + * Loads vocabulary context info into memory (cache). + */ + @EventListener(value = {VocabularyCreatedEvent.class, EvictCacheEvent.class, ContextRefreshedEvent.class}) + public void load() { + this.contexts = new HashMap<>(); + em.createNativeQuery("SELECT ?v ?g WHERE { GRAPH ?g { ?v a ?type . } }") + .setParameter("type", URI.create(Vocabulary.s_c_slovnik)) + .getResultStream().forEach(row -> { + assert row instanceof Object[]; + assert ((Object[]) row).length == 2; + final Object[] bindingSet = (Object[]) row; + final List ctx = contexts.computeIfAbsent((URI) bindingSet[0], (k) -> new ArrayList<>()); + ctx.add((URI) bindingSet[1]); + }); + } + + /** + * Gets identifier of the repository context in which vocabulary with the specified identifier is stored. + * + * @param vocabularyUri Vocabulary identifier + * @return Repository context identifier + */ + public URI getVocabularyContext(URI vocabularyUri) { + if (!contexts.containsKey(vocabularyUri)) { + LOG.debug("No context mapped for vocabulary {}, returning the vocabulary IRI as context identifier.", + uriToString(vocabularyUri)); + return vocabularyUri; + } + final List vocabularyContexts = contexts.get(vocabularyUri); + if (vocabularyContexts.size() > 1) { + throw new AmbiguousVocabularyContextException( + "Multiple repository contexts found for vocabulary " + uriToString(vocabularyUri)); + } + return vocabularyContexts.get(0); + } +} diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/context/DefaultVocabularyContextMapper.java b/src/main/java/cz/cvut/kbss/termit/persistence/context/DefaultVocabularyContextMapper.java new file mode 100644 index 000000000..52b827657 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/persistence/context/DefaultVocabularyContextMapper.java @@ -0,0 +1,53 @@ +package cz.cvut.kbss.termit.persistence.context; + +import cz.cvut.kbss.jopa.exceptions.NoResultException; +import cz.cvut.kbss.jopa.exceptions.NoUniqueResultException; +import cz.cvut.kbss.jopa.model.EntityManager; +import cz.cvut.kbss.termit.exception.AmbiguousVocabularyContextException; +import cz.cvut.kbss.termit.util.Vocabulary; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Profile; +import org.springframework.stereotype.Component; + +import java.net.URI; +import java.util.Objects; + +import static cz.cvut.kbss.termit.util.Utils.uriToString; + +/** + * Default implementation of the context mapper resolves vocabulary context on every call. + *

+ * This incurs a performance penalty of executing a simple query, but does not suffer from potentially stale cache + * data. + */ +@Component +@Profile("no-cache") +public class DefaultVocabularyContextMapper implements VocabularyContextMapper { + + private static final Logger LOG = LoggerFactory.getLogger(DefaultVocabularyContextMapper.class); + + private final EntityManager em; + + public DefaultVocabularyContextMapper(EntityManager em) { + this.em = em; + } + + @Override + public URI getVocabularyContext(URI vocabularyUri) { + Objects.requireNonNull(vocabularyUri); + try { + return em.createNativeQuery("SELECT ?g WHERE { GRAPH ?g { ?vocabulary a ?type . } }", URI.class) + .setParameter("type", URI.create(Vocabulary.s_c_slovnik)) + .setParameter("vocabulary", vocabularyUri) + .getSingleResult(); + } catch (NoResultException e) { + LOG.debug("No context mapped for vocabulary {}, returning the vocabulary IRI as context identifier.", + uriToString(vocabularyUri)); + return vocabularyUri; + } catch (NoUniqueResultException e) { + throw new AmbiguousVocabularyContextException( + "Multiple repository contexts found for vocabulary " + uriToString(vocabularyUri)); + } + } +} diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/DescriptorFactory.java b/src/main/java/cz/cvut/kbss/termit/persistence/context/DescriptorFactory.java similarity index 96% rename from src/main/java/cz/cvut/kbss/termit/persistence/DescriptorFactory.java rename to src/main/java/cz/cvut/kbss/termit/persistence/context/DescriptorFactory.java index fe920c739..329950889 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/DescriptorFactory.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/context/DescriptorFactory.java @@ -12,7 +12,7 @@ * You should have received a copy of the GNU General Public License along with this program. If not, see * . */ -package cz.cvut.kbss.termit.persistence; +package cz.cvut.kbss.termit.persistence.context; import cz.cvut.kbss.jopa.model.EntityManagerFactory; import cz.cvut.kbss.jopa.model.descriptors.Descriptor; @@ -37,9 +37,12 @@ public class DescriptorFactory { private final EntityManagerFactory emf; + private final VocabularyContextMapper contextMapper; + @Autowired - public DescriptorFactory(EntityManagerFactory emf) { + public DescriptorFactory(EntityManagerFactory emf, VocabularyContextMapper contextMapper) { this.emf = emf; + this.contextMapper = contextMapper; } /** @@ -58,9 +61,9 @@ public Descriptor vocabularyDescriptor(Vocabulary vocabulary) { return vocabularyDescriptor(vocabulary.getUri()); } - private static EntityDescriptor assetDescriptor(URI vocabularyUri) { + private EntityDescriptor assetDescriptor(URI vocabularyUri) { Objects.requireNonNull(vocabularyUri); - return new EntityDescriptor(vocabularyUri); + return new EntityDescriptor(contextMapper.getVocabularyContext(vocabularyUri)); } public FieldSpecification fieldSpec(Class entityCls, String attribute) { diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/context/VocabularyContextMapper.java b/src/main/java/cz/cvut/kbss/termit/persistence/context/VocabularyContextMapper.java new file mode 100644 index 000000000..b7adc5282 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/persistence/context/VocabularyContextMapper.java @@ -0,0 +1,36 @@ +package cz.cvut.kbss.termit.persistence.context; + +import cz.cvut.kbss.termit.model.Vocabulary; + +import java.net.URI; +import java.util.Objects; + +/** + * Maps vocabularies to repository contexts in which they are stored. + */ +public interface VocabularyContextMapper { + + /** + * Gets identifier of the repository context in which the specified vocabulary is stored. + * + * @param vocabulary Vocabulary whose context to retrieve + * @return Repository context identifier + */ + default URI getVocabularyContext(Vocabulary vocabulary) { + Objects.requireNonNull(vocabulary); + return getVocabularyContext(vocabulary.getUri()); + } + + /** + * Gets identifier of the repository context in which vocabulary with the specified identifier is stored. + *

+ * If the vocabulary does not exist yet (and thus has no repository context), the vocabulary identifier is returned + * as context. + * + * @param vocabularyUri Vocabulary identifier + * @return Repository context identifier + * @throws cz.cvut.kbss.termit.exception.AmbiguousVocabularyContextException In case multiple contexts for a + * vocabulary are found + */ + URI getVocabularyContext(URI vocabularyUri); +} diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/AssetDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/AssetDao.java index 9b7c916dd..8072b68d9 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/AssetDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/AssetDao.java @@ -21,7 +21,7 @@ import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.comment.Comment; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.util.Vocabulary; import cz.cvut.kbss.termit.util.Configuration.Persistence; diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/ResourceDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/ResourceDao.java index 38f52ab0a..450fa0603 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/ResourceDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/ResourceDao.java @@ -25,7 +25,7 @@ import cz.cvut.kbss.termit.model.resource.Document; import cz.cvut.kbss.termit.model.resource.File; import cz.cvut.kbss.termit.model.resource.Resource; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.util.Configuration; import cz.cvut.kbss.termit.util.Vocabulary; import org.springframework.context.event.EventListener; diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java index 3799a3b72..d4d735694 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java @@ -26,7 +26,7 @@ import cz.cvut.kbss.termit.model.Term; import cz.cvut.kbss.termit.model.Vocabulary; import cz.cvut.kbss.termit.model.util.HasIdentifier; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.persistence.dao.util.Cache; import cz.cvut.kbss.termit.persistence.dao.util.SparqlResultToTermInfoMapper; import cz.cvut.kbss.termit.persistence.snapshot.AssetSnapshotLoader; diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDao.java index a8f54626b..a5e81e0d1 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDao.java @@ -27,7 +27,7 @@ import cz.cvut.kbss.termit.model.Glossary; import cz.cvut.kbss.termit.model.Vocabulary; import cz.cvut.kbss.termit.model.validation.ValidationResult; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.persistence.snapshot.AssetSnapshotLoader; import cz.cvut.kbss.termit.persistence.validation.VocabularyContentValidator; import cz.cvut.kbss.termit.service.snapshot.SnapshotProvider; diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/comment/CommentDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/comment/CommentDao.java index 0dac937ae..7118bcc1c 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/comment/CommentDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/comment/CommentDao.java @@ -8,7 +8,7 @@ import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.comment.Comment; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.util.Configuration; import cz.cvut.kbss.termit.util.Constants; import cz.cvut.kbss.termit.util.Utils; diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryService.java index c120a3c08..010b6cd05 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryService.java @@ -140,7 +140,7 @@ public T getRequiredReference(URI id) { private Class resolveGenericType() { // Adapted from https://gist.github.com/yunspace/930d4d40a787a1f6a7d1 final List typeParameters = - new TypeResolver().resolve(this.getClass()).typeParametersFor(BaseRepositoryService.class); + new TypeResolver().resolve(this.getClass()).typeParametersFor(BaseRepositoryService.class); assert typeParameters.size() == 1; return (Class) typeParameters.get(0).getErasedType(); } @@ -165,6 +165,7 @@ public void persist(@NonNull T instance) { Objects.requireNonNull(instance); prePersist(instance); getPrimaryDao().persist(instance); + postPersist(instance); } /** @@ -178,6 +179,15 @@ protected void prePersist(@NonNull T instance) { validate(instance); } + /** + * Override this method to plug custom behavior into the transactional cycle of {@link #persist(HasIdentifier)}. + * + * @param instance The persisted instance, not {@code null} + */ + protected void postPersist(@NonNull T instance) { + // Do nothing + } + /** * Merges the specified updated instance into the repository. * diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryService.java index f754a3dcf..88a59cf98 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryService.java @@ -3,6 +3,7 @@ import cz.cvut.kbss.termit.dto.AggregatedChangeInfo; import cz.cvut.kbss.termit.dto.Snapshot; import cz.cvut.kbss.termit.dto.listing.TermDto; +import cz.cvut.kbss.termit.event.VocabularyCreatedEvent; import cz.cvut.kbss.termit.exception.AssetRemovalException; import cz.cvut.kbss.termit.exception.NotFoundException; import cz.cvut.kbss.termit.exception.importing.VocabularyImportException; @@ -31,6 +32,8 @@ import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @@ -46,7 +49,8 @@ @CacheConfig(cacheNames = "vocabularies") @Service -public class VocabularyRepositoryService extends BaseAssetRepositoryService implements VocabularyService { +public class VocabularyRepositoryService extends BaseAssetRepositoryService + implements ApplicationEventPublisherAware, VocabularyService { private static final Logger LOG = LoggerFactory.getLogger(VocabularyRepositoryService.class); @@ -62,6 +66,8 @@ public class VocabularyRepositoryService extends BaseAssetRepositoryService new NotFoundException("No version valid at " + at + " exists.")); } + + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } } diff --git a/src/test/java/cz/cvut/kbss/termit/environment/config/TestConfig.java b/src/test/java/cz/cvut/kbss/termit/environment/config/TestConfig.java index 9b0f513fe..ac3213a01 100644 --- a/src/test/java/cz/cvut/kbss/termit/environment/config/TestConfig.java +++ b/src/test/java/cz/cvut/kbss/termit/environment/config/TestConfig.java @@ -26,8 +26,6 @@ public class TestConfig { @Autowired private Configuration configuration; -// @Bean -// @Primary public Configuration configuration() { return configuration; } diff --git a/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceConfig.java b/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceConfig.java index bdea726a9..15d7d0a93 100644 --- a/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceConfig.java +++ b/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceConfig.java @@ -1,13 +1,16 @@ /** * TermIt Copyright (C) 2019 Czech Technical University in Prague *

- * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later + * version. *

- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. *

- * You should have received a copy of the GNU General Public License along with this program. If not, see . + * You should have received a copy of the GNU General Public License along with this program. If not, see + * . */ package cz.cvut.kbss.termit.environment.config; diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/context/CachingVocabularyContextMapperTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/context/CachingVocabularyContextMapperTest.java new file mode 100644 index 000000000..ce09af0d9 --- /dev/null +++ b/src/test/java/cz/cvut/kbss/termit/persistence/context/CachingVocabularyContextMapperTest.java @@ -0,0 +1,85 @@ +package cz.cvut.kbss.termit.persistence.context; + +import cz.cvut.kbss.jopa.model.EntityManager; +import cz.cvut.kbss.jopa.model.descriptors.Descriptor; +import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor; +import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.exception.AmbiguousVocabularyContextException; +import cz.cvut.kbss.termit.exception.NotFoundException; +import cz.cvut.kbss.termit.model.Vocabulary; +import cz.cvut.kbss.termit.persistence.dao.BaseDaoTestRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.IntStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class CachingVocabularyContextMapperTest extends BaseDaoTestRunner { + + @Autowired + private EntityManager em; + + private CachingVocabularyContextMapper sut; + + @BeforeEach + void setUp() { + this.sut = new CachingVocabularyContextMapper(em); + } + + @Test + void getVocabularyContextResolvesVocabularyContext() { + Map map = generateVocabularies(); + sut.load(); + map.forEach((v, ctx) -> assertEquals(ctx, sut.getVocabularyContext(v))); + } + + private Map generateVocabularies() { + final Map map = new HashMap<>(); + transactional(() -> IntStream.range(0, Generator.randomInt(2, 5)).forEach(i -> { + final Vocabulary v = Generator.generateVocabularyWithId(); + final URI context = Generator.randomBoolean() ? Generator.generateUri() : v.getUri(); + final Descriptor descriptor = new EntityDescriptor(context); + em.persist(v, descriptor); + map.put(v, context); + })); + return map; + } + + @Test + void getVocabularyContextReturnsVocabularyIriWhenNoContextForSpecifiedVocabularyExists() { + sut.load(); + final URI vocabularyUri = Generator.generateUri(); + assertEquals(vocabularyUri, sut.getVocabularyContext(vocabularyUri)); + } + + @Test + void getVocabularyContextThrowsAmbiguousVocabularyContextExceptionWhenMultipleContextsForVocabularyAreDetermined() { + final Vocabulary v = Generator.generateVocabularyWithId(); + transactional(() -> em.persist(v, new EntityDescriptor(v.getUri()))); + transactional(() -> em.persist(v, new EntityDescriptor(Generator.generateUri()))); + sut.load(); + + assertThrows(AmbiguousVocabularyContextException.class, () -> sut.getVocabularyContext(v)); + } + + @Test + void reloadsCachedContextsOnVocabularyCreatedEvent() { + final Vocabulary v = Generator.generateVocabularyWithId(); + transactional(() -> em.persist(v, new EntityDescriptor(v.getUri()))); + sut.load(); + final Vocabulary newVocabulary = Generator.generateVocabularyWithId(); + final URI context = Generator.generateUri(); + transactional(() -> em.persist(newVocabulary, new EntityDescriptor(context))); + + // No mapping -> return vocabulary IRI + assertEquals(newVocabulary.getUri(), sut.getVocabularyContext(newVocabulary)); + sut.load(); // Event handler + assertEquals(context, sut.getVocabularyContext(newVocabulary)); + } +} diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/context/DefaultVocabularyContextMapperTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/context/DefaultVocabularyContextMapperTest.java new file mode 100644 index 000000000..c756eac29 --- /dev/null +++ b/src/test/java/cz/cvut/kbss/termit/persistence/context/DefaultVocabularyContextMapperTest.java @@ -0,0 +1,53 @@ +package cz.cvut.kbss.termit.persistence.context; + +import cz.cvut.kbss.jopa.model.EntityManager; +import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor; +import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.exception.AmbiguousVocabularyContextException; +import cz.cvut.kbss.termit.model.Vocabulary; +import cz.cvut.kbss.termit.persistence.dao.BaseDaoTestRunner; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class DefaultVocabularyContextMapperTest extends BaseDaoTestRunner { + + @Autowired + private EntityManager em; + + private DefaultVocabularyContextMapper sut; + + @BeforeEach + void setUp() { + this.sut = new DefaultVocabularyContextMapper(em); + } + + @Test + void getVocabularyContextResolvesVocabularyContextFromRepository() { + final URI context = Generator.generateUri(); + final Vocabulary vocabulary = Generator.generateVocabularyWithId(); + transactional(() -> em.persist(vocabulary, new EntityDescriptor(context))); + + assertEquals(context, sut.getVocabularyContext(vocabulary)); + } + + @Test + void getVocabularyContextReturnsVocabularyUriWhenNoContextIsFoundInRepository() { + final Vocabulary vocabulary = Generator.generateVocabularyWithId(); + assertEquals(vocabulary.getUri(), sut.getVocabularyContext(vocabulary.getUri())); + } + + @Test + void getVocabularyContextThrowsAmbiguousVocabularyContextExceptionWhenMultipleContextsForVocabularyAreDetermined() { + final Vocabulary v = Generator.generateVocabularyWithId(); + transactional(() -> em.persist(v, new EntityDescriptor(v.getUri()))); + transactional(() -> em.persist(v, new EntityDescriptor(Generator.generateUri()))); + + assertThrows(AmbiguousVocabularyContextException.class, () -> sut.getVocabularyContext(v)); + } +} diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/DescriptorFactoryTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/context/DescriptorFactoryTest.java similarity index 99% rename from src/test/java/cz/cvut/kbss/termit/persistence/DescriptorFactoryTest.java rename to src/test/java/cz/cvut/kbss/termit/persistence/context/DescriptorFactoryTest.java index 8a41da414..fd398d6a1 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/DescriptorFactoryTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/context/DescriptorFactoryTest.java @@ -12,7 +12,7 @@ * You should have received a copy of the GNU General Public License along with this program. If not, see * . */ -package cz.cvut.kbss.termit.persistence; +package cz.cvut.kbss.termit.persistence.context; import cz.cvut.kbss.jopa.model.descriptors.Descriptor; import cz.cvut.kbss.jopa.model.metamodel.FieldSpecification; diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseTermDaoTestRunner.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseTermDaoTestRunner.java index 82bacd6ab..5f44b7e1c 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseTermDaoTestRunner.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseTermDaoTestRunner.java @@ -3,8 +3,7 @@ import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.model.Vocabulary; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; -import org.junit.jupiter.api.BeforeEach; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import org.springframework.beans.factory.annotation.Autowired; public class BaseTermDaoTestRunner extends BaseDaoTestRunner { diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/ResourceDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/ResourceDaoTest.java index a99fa0681..100f25e06 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/ResourceDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/ResourceDaoTest.java @@ -25,7 +25,7 @@ import cz.cvut.kbss.termit.model.resource.Document; import cz.cvut.kbss.termit.model.resource.File; import cz.cvut.kbss.termit.model.resource.Resource; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoExactMatchTermsTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoExactMatchTermsTest.java index 656425d2b..cab4b8f27 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoExactMatchTermsTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoExactMatchTermsTest.java @@ -7,13 +7,11 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.jopa.vocabulary.SKOS; import cz.cvut.kbss.termit.dto.TermInfo; import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.model.Term; -import cz.cvut.kbss.termit.model.Vocabulary; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -26,7 +24,6 @@ import org.eclipse.rdf4j.repository.RepositoryConnection; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; public class TermDaoExactMatchTermsTest extends BaseTermDaoTestRunner { diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDaoTest.java index e0e1a62cd..c00ca453d 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/VocabularyDaoTest.java @@ -27,7 +27,7 @@ import cz.cvut.kbss.termit.model.changetracking.UpdateChangeRecord; import cz.cvut.kbss.termit.model.resource.Document; import cz.cvut.kbss.termit.model.resource.File; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.ValueFactory; import org.eclipse.rdf4j.model.vocabulary.RDF; diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/changetracking/ChangeTrackingHelperDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/changetracking/ChangeTrackingHelperDaoTest.java index bd7140189..64484e6bb 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/changetracking/ChangeTrackingHelperDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/changetracking/ChangeTrackingHelperDaoTest.java @@ -6,7 +6,7 @@ import cz.cvut.kbss.termit.exception.NotFoundException; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.Vocabulary; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.persistence.dao.BaseDaoTestRunner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/skos/SKOSImporterTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/skos/SKOSImporterTest.java index f139db16b..9051be86a 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/skos/SKOSImporterTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/skos/SKOSImporterTest.java @@ -8,7 +8,7 @@ import cz.cvut.kbss.termit.exception.importing.VocabularyImportException; import cz.cvut.kbss.termit.model.Glossary; import cz.cvut.kbss.termit.model.User; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.persistence.dao.BaseDaoTestRunner; import cz.cvut.kbss.termit.persistence.dao.VocabularyDao; import cz.cvut.kbss.termit.util.Constants; diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/snapshot/CascadingSnapshotCreatorTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/snapshot/CascadingSnapshotCreatorTest.java index 3e6d6d399..82f329e47 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/snapshot/CascadingSnapshotCreatorTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/snapshot/CascadingSnapshotCreatorTest.java @@ -11,7 +11,7 @@ import cz.cvut.kbss.termit.model.Vocabulary; import cz.cvut.kbss.termit.model.resource.Document; import cz.cvut.kbss.termit.model.util.HasIdentifier; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.persistence.dao.BaseDaoTestRunner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/cz/cvut/kbss/termit/service/BaseServiceTestRunner.java b/src/test/java/cz/cvut/kbss/termit/service/BaseServiceTestRunner.java index dc1f1b597..e4b707933 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/BaseServiceTestRunner.java +++ b/src/test/java/cz/cvut/kbss/termit/service/BaseServiceTestRunner.java @@ -13,8 +13,6 @@ import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.termit.environment.TransactionalTestRunner; -import cz.cvut.kbss.termit.environment.config.TestConfig; -import cz.cvut.kbss.termit.environment.config.TestPersistenceAspectsConfig; import cz.cvut.kbss.termit.environment.config.TestPersistenceConfig; import cz.cvut.kbss.termit.environment.config.TestServiceConfig; import cz.cvut.kbss.termit.util.Configuration; diff --git a/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackerTest.java b/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackerTest.java index 1019eeb6b..0bace7d6d 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackerTest.java @@ -13,7 +13,7 @@ import cz.cvut.kbss.termit.model.changetracking.PersistChangeRecord; import cz.cvut.kbss.termit.model.changetracking.UpdateChangeRecord; import cz.cvut.kbss.termit.model.util.HasIdentifier; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackingTest.java b/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackingTest.java index 4403c93c2..9d2370b01 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackingTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/changetracking/ChangeTrackingTest.java @@ -14,7 +14,7 @@ import cz.cvut.kbss.termit.model.changetracking.PersistChangeRecord; import cz.cvut.kbss.termit.model.changetracking.UpdateChangeRecord; import cz.cvut.kbss.termit.model.resource.File; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.persistence.dao.changetracking.ChangeRecordDao; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import cz.cvut.kbss.termit.service.repository.ResourceRepositoryService; diff --git a/src/test/java/cz/cvut/kbss/termit/service/comment/CommentServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/comment/CommentServiceTest.java index 49a083aea..0196bc17b 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/comment/CommentServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/comment/CommentServiceTest.java @@ -11,7 +11,7 @@ import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.comment.Comment; import cz.cvut.kbss.termit.model.comment.CommentReaction; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import cz.cvut.kbss.termit.util.Configuration; import cz.cvut.kbss.termit.util.Vocabulary; diff --git a/src/test/java/cz/cvut/kbss/termit/service/document/AnnotationGeneratorTest.java b/src/test/java/cz/cvut/kbss/termit/service/document/AnnotationGeneratorTest.java index 9beb92014..31e52a887 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/document/AnnotationGeneratorTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/document/AnnotationGeneratorTest.java @@ -28,7 +28,7 @@ import cz.cvut.kbss.termit.model.assignment.TermOccurrence; import cz.cvut.kbss.termit.model.resource.File; import cz.cvut.kbss.termit.model.selector.TextQuoteSelector; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.persistence.dao.TermDao; import cz.cvut.kbss.termit.persistence.dao.TermOccurrenceDao; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; diff --git a/src/test/java/cz/cvut/kbss/termit/service/export/SKOSVocabularyExporterTest.java b/src/test/java/cz/cvut/kbss/termit/service/export/SKOSVocabularyExporterTest.java index 33b7b9c50..a8b9cc594 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/export/SKOSVocabularyExporterTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/export/SKOSVocabularyExporterTest.java @@ -7,7 +7,7 @@ import cz.cvut.kbss.termit.model.Term; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.Vocabulary; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import cz.cvut.kbss.termit.util.Configuration; import cz.cvut.kbss.termit.util.Constants; diff --git a/src/test/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryServiceTest.java index 6e4e7006b..a2b64c6b6 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/repository/BaseRepositoryServiceTest.java @@ -88,6 +88,17 @@ void persistExecutesPrePersistMethodBeforePersistOnDao() { inOrder.verify(userAccountDaoMock).persist(user); } + @Test + void persistExecutesPostPersistMethodAfterPersistOnDao() { + final UserAccount user = Generator.generateUserAccountWithPassword(); + final BaseRepositoryServiceImpl sut = spy(new BaseRepositoryServiceImpl(userAccountDaoMock, validator)); + + sut.persist(user); + final InOrder inOrder = Mockito.inOrder(sut, userAccountDaoMock); + inOrder.verify(userAccountDaoMock).persist(user); + inOrder.verify(sut).postPersist(user); + } + @Test void updateExecutesTransactionalUpdate() { final UserAccount user = Generator.generateUserAccountWithPassword(); diff --git a/src/test/java/cz/cvut/kbss/termit/service/repository/ChangeRecordServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/repository/ChangeRecordServiceTest.java index 42b5e56d9..1120118a0 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/repository/ChangeRecordServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/repository/ChangeRecordServiceTest.java @@ -8,7 +8,7 @@ import cz.cvut.kbss.termit.model.Vocabulary; import cz.cvut.kbss.termit.model.changetracking.AbstractChangeRecord; import cz.cvut.kbss.termit.model.changetracking.UpdateChangeRecord; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/src/test/java/cz/cvut/kbss/termit/service/repository/ResourceRepositoryServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/repository/ResourceRepositoryServiceTest.java index 843da1e1a..a4f8af956 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/repository/ResourceRepositoryServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/repository/ResourceRepositoryServiceTest.java @@ -33,7 +33,7 @@ import cz.cvut.kbss.termit.model.resource.Resource; import cz.cvut.kbss.termit.model.selector.Selector; import cz.cvut.kbss.termit.model.selector.TextQuoteSelector; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import cz.cvut.kbss.termit.util.Vocabulary; import org.eclipse.rdf4j.model.ValueFactory; diff --git a/src/test/java/cz/cvut/kbss/termit/service/repository/TermRepositoryServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/repository/TermRepositoryServiceTest.java index b1beff2fe..0a14de450 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/repository/TermRepositoryServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/repository/TermRepositoryServiceTest.java @@ -30,7 +30,7 @@ import cz.cvut.kbss.termit.model.assignment.TermOccurrence; import cz.cvut.kbss.termit.model.resource.Document; import cz.cvut.kbss.termit.model.resource.File; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import cz.cvut.kbss.termit.util.Constants; import org.eclipse.rdf4j.common.iteration.Iterations; diff --git a/src/test/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryServiceTest.java index eacb71715..92e485001 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/repository/VocabularyRepositoryServiceTest.java @@ -19,6 +19,7 @@ import cz.cvut.kbss.termit.dto.Snapshot; import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.event.VocabularyCreatedEvent; import cz.cvut.kbss.termit.exception.NotFoundException; import cz.cvut.kbss.termit.exception.ResourceExistsException; import cz.cvut.kbss.termit.exception.TermItException; @@ -29,16 +30,20 @@ import cz.cvut.kbss.termit.model.Vocabulary; import cz.cvut.kbss.termit.model.changetracking.AbstractChangeRecord; import cz.cvut.kbss.termit.model.changetracking.PersistChangeRecord; -import cz.cvut.kbss.termit.persistence.DescriptorFactory; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.service.BaseServiceTestRunner; import cz.cvut.kbss.termit.service.IdentifierResolver; import cz.cvut.kbss.termit.util.Configuration; import cz.cvut.kbss.termit.util.Constants; import org.hamcrest.collection.IsEmptyCollection; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.mock.web.MockMultipartFile; import org.springframework.web.multipart.MultipartFile; @@ -53,9 +58,13 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.verify; class VocabularyRepositoryServiceTest extends BaseServiceTestRunner { + @Autowired + private ApplicationEventPublisher eventPublisher; + @Autowired private Configuration config; @@ -75,6 +84,12 @@ void setUp() { this.user = Generator.generateUserAccountWithPassword(); transactional(() -> em.persist(user)); Environment.setCurrentUser(user); + sut.setApplicationEventPublisher(eventPublisher); + } + + @AfterEach + void tearDown() { + Mockito.reset(eventPublisher); } @Test @@ -94,6 +109,16 @@ void persistGeneratesPersistChangeRecord() { assertNotNull(record.getTimestamp()); } + @Test + void persistPublishesVocabularyCreatedEvent() { + final Vocabulary vocabulary = Generator.generateVocabularyWithId(); + + sut.persist(vocabulary); + final ArgumentCaptor captor = ArgumentCaptor.forClass(VocabularyCreatedEvent.class); + verify(eventPublisher).publishEvent(captor.capture()); + assertNotNull(captor.getValue()); + } + @Test void persistThrowsValidationExceptionWhenVocabularyNameIsBlank() { final Vocabulary vocabulary = Generator.generateVocabularyWithId(); @@ -369,6 +394,17 @@ void createSnapshotCreatesSnapshotOfSpecifiedVocabulary() { assertNotNull(result); } + @Test + void createSnapshotPublishesVocabularyCreatedEvent() { + final Vocabulary vocabulary = Generator.generateVocabularyWithId(); + transactional(() -> em.persist(vocabulary, descriptorFor(vocabulary))); + + sut.createSnapshot(vocabulary); + final ArgumentCaptor captor = ArgumentCaptor.forClass(VocabularyCreatedEvent.class); + verify(eventPublisher).publishEvent(captor.capture()); + assertNotNull(captor.getValue()); + } + @Test void findVersionValidAtThrowsNotFoundExceptionWhenNoValidSnapshotExists() { final Vocabulary vocabulary = Generator.generateVocabularyWithId();