From 0fadbe77fb227553f2bce66b654202d6d988d361 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Thu, 11 Jul 2024 16:32:16 +0200 Subject: [PATCH 01/11] [Upd] Update to JOPA 2.0.2, refactor getReference methods. Since getReference has been reimplemented in JOPA 2.0.2, we needed to adjust the behavior in TermIt as well. This was an opportunity to simplify it as well and replace getReference and getRequiredReference with just getReference. --- .../kbss/termit/persistence/dao/BaseDao.java | 8 ++-- .../termit/persistence/dao/GenericDao.java | 5 +-- .../termit/persistence/dao/VocabularyDao.java | 4 +- .../CascadingVocabularySnapshotRemover.java | 4 +- .../kbss/termit/rest/OidcUserController.java | 22 ++++++----- .../kbss/termit/rest/ResourceController.java | 4 +- .../cvut/kbss/termit/rest/TermController.java | 2 +- .../cvut/kbss/termit/rest/UserController.java | 2 +- .../kbss/termit/rest/UserGroupController.java | 2 +- .../termit/rest/VocabularyController.java | 37 ++++++++++++------- .../rest/handler/RestExceptionHandler.java | 6 +++ .../rest/readonly/ReadOnlyTermController.java | 8 ++-- .../business/AccessControlListService.java | 2 +- .../service/business/ResourceService.java | 16 +++----- .../termit/service/business/RudService.java | 11 +----- .../business/TermOccurrenceService.java | 11 ------ .../termit/service/business/TermService.java | 26 +++---------- .../termit/service/business/UserService.java | 27 +++++++++----- .../service/business/VocabularyService.java | 10 +---- .../readonly/ReadOnlyTermService.java | 4 +- .../repository/BaseRepositoryService.java | 29 ++++----------- .../RepositoryAccessControlListService.java | 2 +- .../TermOccurrenceRepositoryService.java | 7 +--- .../repository/TermRepositoryService.java | 6 +-- .../kbss/termit/environment/Transaction.java | 22 ++++++++++- .../environment/TransactionalTestRunner.java | 4 ++ .../termit/persistence/dao/BaseDaoTest.java | 31 +++++++++------- .../persistence/dao/ResourceDaoTest.java | 2 +- .../termit/rest/ResourceControllerTest.java | 6 +-- .../kbss/termit/rest/TermControllerTest.java | 6 +-- .../kbss/termit/rest/UserControllerTest.java | 2 +- .../termit/rest/UserGroupControllerTest.java | 2 +- .../termit/rest/VocabularyControllerTest.java | 8 ++-- .../readonly/ReadOnlyTermControllerTest.java | 12 +++--- .../service/business/ResourceServiceTest.java | 27 +++++--------- .../service/business/TermServiceTest.java | 20 +++------- .../readonly/ReadOnlyTermServiceTest.java | 2 +- .../repository/BaseRepositoryServiceTest.java | 15 ++++++++ ...epositoryAccessControlListServiceTest.java | 4 +- 39 files changed, 200 insertions(+), 218 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseDao.java index a87fb845d..9ba16facf 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseDao.java @@ -69,10 +69,10 @@ public Optional find(URI id) { } @Override - public Optional getReference(URI id) { + public T getReference(URI id) { Objects.requireNonNull(id); try { - return Optional.ofNullable(em.getReference(type, id, getDescriptor())); + return em.getReference(type, id, getDescriptor()); } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -123,8 +123,8 @@ public void remove(T entity) { Objects.requireNonNull(entity); Objects.requireNonNull(entity.getUri()); try { - final Optional reference = getReference(entity.getUri()); - reference.ifPresent(em::remove); + final Optional toRemove = find(entity.getUri()); + toRemove.ifPresent(em::remove); } catch (RuntimeException e) { throw new PersistenceException(e); } diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/GenericDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/GenericDao.java index 376918051..82267ee72 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/GenericDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/GenericDao.java @@ -55,10 +55,9 @@ public interface GenericDao { * operations. * * @param id Identifier - * @return {@code Optional} containing a reference to a matching instance or an empty {@code Optional }if no such - * instance exists + * @return Reference to an entity with the specified identifier */ - Optional getReference(URI id); + T getReference(URI id); /** * Detaches the specified entity from the current persistence context. 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 d3e05dd12..93180ff65 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 @@ -116,10 +116,10 @@ public Optional find(URI id) { } @Override - public Optional getReference(URI id) { + public Vocabulary getReference(URI id) { Objects.requireNonNull(id); try { - return Optional.ofNullable(em.getReference(type, id, descriptorFactory.vocabularyDescriptor(id))); + return em.getReference(type, id, descriptorFactory.vocabularyDescriptor(id)); } catch (RuntimeException e) { throw new PersistenceException(e); } diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/snapshot/CascadingVocabularySnapshotRemover.java b/src/main/java/cz/cvut/kbss/termit/persistence/snapshot/CascadingVocabularySnapshotRemover.java index c192609a8..28536ecba 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/snapshot/CascadingVocabularySnapshotRemover.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/snapshot/CascadingVocabularySnapshotRemover.java @@ -19,7 +19,6 @@ import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.termit.dto.Snapshot; -import cz.cvut.kbss.termit.exception.NotFoundException; import cz.cvut.kbss.termit.exception.UnsupportedAssetOperationException; import cz.cvut.kbss.termit.exception.UnsupportedOperationException; import cz.cvut.kbss.termit.model.Vocabulary; @@ -48,8 +47,7 @@ public CascadingVocabularySnapshotRemover(VocabularyDao vocabularyDao, EntityMan public void removeSnapshot(Snapshot snapshot) { Objects.requireNonNull(snapshot); ensureAssetType(snapshot); - final Vocabulary toRemove = vocabularyDao.getReference(snapshot.getUri()).orElseThrow( - () -> NotFoundException.create(Vocabulary.class, snapshot.getUri())); + final Vocabulary toRemove = vocabularyDao.getReference(snapshot.getUri()); if (!toRemove.isSnapshot()) { throw new UnsupportedOperationException("Vocabulary " + toRemove + " is not a snapshot."); } diff --git a/src/main/java/cz/cvut/kbss/termit/rest/OidcUserController.java b/src/main/java/cz/cvut/kbss/termit/rest/OidcUserController.java index cf26c8c56..2a5931b02 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/OidcUserController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/OidcUserController.java @@ -47,7 +47,7 @@ /** * Controller for basic user-related operations that do not involve editing/adding/removing user accounts. - * + *

* Enabled when OIDC security is used. */ @ConditionalOnProperty(prefix = "termit.security", name = "provider", havingValue = "oidc") @@ -76,7 +76,8 @@ public List getAll() { @Operation(security = {@SecurityRequirement(name = "bearer-key")}, description = "Gets the currently logged-in user.") @ApiResponse(responseCode = "200", description = "Metadata of the current user's account.") - @GetMapping(value = UserController.CURRENT_USER_PATH, produces = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) + @GetMapping(value = UserController.CURRENT_USER_PATH, + produces = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) public UserAccount getCurrent() { return userService.getCurrent(); } @@ -89,14 +90,15 @@ public UserAccount getCurrent() { }) @GetMapping(value = "/{localName}/managed-assets", produces = {MediaType.APPLICATION_JSON_VALUE, JsonLd.MEDIA_TYPE}) @PreAuthorize("hasRole('" + SecurityConstants.ROLE_ADMIN + "')") - public List getManagedAssets(@Parameter(description = UserController.UserControllerDoc.ID_LOCAL_NAME_DESCRIPTION, - example = UserController.UserControllerDoc.ID_LOCAL_NAME_EXAMPLE) - @PathVariable String localName, - @Parameter(description = UserController.UserControllerDoc.ID_NAMESPACE_DESCRIPTION, - example = UserController.UserControllerDoc.ID_NAMESPACE_EXAMPLE) - @RequestParam(name = Constants.QueryParams.NAMESPACE, - required = false) Optional namespace) { + public List getManagedAssets( + @Parameter(description = UserController.UserControllerDoc.ID_LOCAL_NAME_DESCRIPTION, + example = UserController.UserControllerDoc.ID_LOCAL_NAME_EXAMPLE) + @PathVariable String localName, + @Parameter(description = UserController.UserControllerDoc.ID_NAMESPACE_DESCRIPTION, + example = UserController.UserControllerDoc.ID_NAMESPACE_EXAMPLE) + @RequestParam(name = Constants.QueryParams.NAMESPACE, + required = false) Optional namespace) { final URI id = idResolver.resolveIdentifier(namespace.orElse(config.getNamespace().getUser()), localName); - return userService.getManagedAssets(userService.getRequiredReference(id)); + return userService.getManagedAssets(userService.getReference(id)); } } diff --git a/src/main/java/cz/cvut/kbss/termit/rest/ResourceController.java b/src/main/java/cz/cvut/kbss/termit/rest/ResourceController.java index ef3c155c2..f389a328a 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/ResourceController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/ResourceController.java @@ -235,7 +235,7 @@ public List getFiles(@Parameter(description = ResourceControllerDoc.ID_LOC @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getResource()), localName); - return resourceService.getFiles(resourceService.getRequiredReference(identifier)); + return resourceService.getFiles(resourceService.getReference(identifier)); } private String resourceNamespace(Optional namespace) { @@ -359,7 +359,7 @@ public List getHistory( @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { final Resource resource = resourceService - .getRequiredReference(resolveIdentifier(resourceNamespace(namespace), localName)); + .getReference(resolveIdentifier(resourceNamespace(namespace), localName)); return resourceService.getChanges(resource); } diff --git a/src/main/java/cz/cvut/kbss/termit/rest/TermController.java b/src/main/java/cz/cvut/kbss/termit/rest/TermController.java index 834b69d36..beec58274 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/TermController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/TermController.java @@ -220,7 +220,7 @@ public ResponseEntity checkTerms( @Parameter(description = "Language of the label.") @RequestParam(name = "language", required = false) String language) { final URI vocabularyUri = getVocabularyUri(namespace, localName); - final Vocabulary vocabulary = termService.getRequiredVocabularyReference(vocabularyUri); + final Vocabulary vocabulary = termService.getVocabularyReference(vocabularyUri); if (prefLabel != null) { final boolean exists = termService.existsInVocabulary(prefLabel, vocabulary, language); return new ResponseEntity<>(exists ? HttpStatus.OK : HttpStatus.NOT_FOUND); diff --git a/src/main/java/cz/cvut/kbss/termit/rest/UserController.java b/src/main/java/cz/cvut/kbss/termit/rest/UserController.java index f36881c0e..4f713eba8 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/UserController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/UserController.java @@ -220,7 +220,7 @@ public List getManagedAssets(@Parameter(description = UserControll @RequestParam(name = Constants.QueryParams.NAMESPACE, required = false) Optional namespace) { final URI id = idResolver.resolveIdentifier(namespace.orElse(config.getNamespace().getUser()), localName); - return userService.getManagedAssets(userService.getRequiredReference(id)); + return userService.getManagedAssets(userService.getReference(id)); } /** diff --git a/src/main/java/cz/cvut/kbss/termit/rest/UserGroupController.java b/src/main/java/cz/cvut/kbss/termit/rest/UserGroupController.java index fe27aeb7a..fa5df36c8 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/UserGroupController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/UserGroupController.java @@ -109,7 +109,7 @@ public void remove(@Parameter(description = UserGroupControllerDoc.ID_LOCAL_NAME example = UserGroupControllerDoc.ID_LOCAL_NAME_EXAMPLE) @PathVariable String fragment) { final URI uri = resolveIdentifier(UserGroup.NAMESPACE, fragment); - final UserGroup toRemove = groupService.getRequiredReference(uri); + final UserGroup toRemove = groupService.getReference(uri); groupService.remove(toRemove); LOG.debug("Group {} removed.", toRemove); } diff --git a/src/main/java/cz/cvut/kbss/termit/rest/VocabularyController.java b/src/main/java/cz/cvut/kbss/termit/rest/VocabularyController.java index eeecfee63..4c42a4513 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/VocabularyController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/VocabularyController.java @@ -47,7 +47,16 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.server.ResponseStatusException; @@ -139,7 +148,7 @@ public Collection getImports(@Parameter(description = ApiDoc.ID_LOCAL_NAME_ example = ApiDoc.ID_NAMESPACE_EXAMPLE) @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { - final Vocabulary vocabulary = vocabularyService.getRequiredReference( + final Vocabulary vocabulary = vocabularyService.getReference( resolveVocabularyUri(localName, namespace)); return vocabularyService.getTransitivelyImportedVocabularies(vocabulary); } @@ -158,7 +167,7 @@ public Collection getRelated(@Parameter(description = ApiDoc.ID_LOCAL_NAME_ example = ApiDoc.ID_NAMESPACE_EXAMPLE) @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { - final Vocabulary vocabulary = vocabularyService.getRequiredReference( + final Vocabulary vocabulary = vocabularyService.getReference( resolveVocabularyUri(localName, namespace)); return vocabularyService.getRelatedVocabularies(vocabulary); } @@ -232,7 +241,7 @@ public List getHistory( example = ApiDoc.ID_NAMESPACE_EXAMPLE) @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { - final Vocabulary vocabulary = vocabularyService.getRequiredReference( + final Vocabulary vocabulary = vocabularyService.getReference( resolveVocabularyUri(localName, namespace)); return vocabularyService.getChanges(vocabulary); } @@ -253,7 +262,7 @@ public List getHistoryOfContent( example = ApiDoc.ID_NAMESPACE_EXAMPLE) @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { - final Vocabulary vocabulary = vocabularyService.getRequiredReference( + final Vocabulary vocabulary = vocabularyService.getReference( resolveVocabularyUri(localName, namespace)); return vocabularyService.getChangesOfContent(vocabulary); } @@ -342,7 +351,7 @@ public void removeVocabulary(@Parameter(description = ApiDoc.ID_LOCAL_NAME_DESCR @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary toRemove = vocabularyService.getRequiredReference(identifier); + final Vocabulary toRemove = vocabularyService.getReference(identifier); vocabularyService.remove(toRemove); LOG.debug("Vocabulary {} removed.", toRemove); } @@ -364,7 +373,7 @@ public List validateVocabulary( @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(identifier); + final Vocabulary vocabulary = vocabularyService.getReference(identifier); return vocabularyService.validateContents(vocabulary); } @@ -385,7 +394,7 @@ public ResponseEntity createSnapshot( @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(identifier); + final Vocabulary vocabulary = vocabularyService.getReference(identifier); final Snapshot snapshot = vocabularyService.createSnapshot(vocabulary); LOG.debug("Created snapshot of vocabulary {}.", vocabulary); return ResponseEntity.created( @@ -413,7 +422,7 @@ public ResponseEntity getSnapshots(@Parameter(description = ApiDoc.ID_LOCAL_N example = ApiDocConstants.DATETIME_EXAMPLE) @RequestParam(name = "at", required = false) Optional at) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(identifier); + final Vocabulary vocabulary = vocabularyService.getReference(identifier); if (at.isPresent()) { final Instant instant = RestUtils.parseTimestamp(at.get()); return ResponseEntity.ok(vocabularyService.findVersionValidAt(vocabulary, instant)); @@ -437,7 +446,7 @@ public AccessControlListDto getAccessControlList( @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(identifier); + final Vocabulary vocabulary = vocabularyService.getReference(identifier); return vocabularyService.getAccessControlList(vocabulary); } @@ -459,7 +468,7 @@ public void addAccessControlRecord(@Parameter(description = ApiDoc.ID_LOCAL_NAME @Parameter(description = "Access control record to add.") @RequestBody AccessControlRecord record) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(identifier); + final Vocabulary vocabulary = vocabularyService.getReference(identifier); vocabularyService.addAccessControlRecords(vocabulary, record); LOG.debug("Added access control record to ACL of vocabulary {}.", vocabulary); } @@ -482,7 +491,7 @@ public void removeAccessControlRecord(@Parameter(description = ApiDoc.ID_LOCAL_N @Parameter(description = "Access control record to remove.") @RequestBody AccessControlRecord record) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(identifier); + final Vocabulary vocabulary = vocabularyService.getReference(identifier); vocabularyService.removeAccessControlRecord(vocabulary, record); LOG.debug("Removed access control record from ACL of vocabulary {}.", vocabulary); } @@ -512,7 +521,7 @@ public void updateAccessControlLevel(@Parameter(description = ApiDoc.ID_LOCAL_NA throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Change record identifier does not match URL."); } final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(identifier); + final Vocabulary vocabulary = vocabularyService.getReference(identifier); vocabularyService.updateAccessControlLevel(vocabulary, record); LOG.debug("Updated access control record {} from ACL of vocabulary {}.", record, vocabulary); } @@ -532,7 +541,7 @@ public AccessLevel getAccessLevel(@Parameter(description = ApiDoc.ID_LOCAL_NAME_ @RequestParam(name = QueryParams.NAMESPACE, required = false) Optional namespace) { final URI identifier = resolveIdentifier(namespace.orElse(config.getNamespace().getVocabulary()), localName); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(identifier); + final Vocabulary vocabulary = vocabularyService.getReference(identifier); return vocabularyService.getAccessLevel(vocabulary); } diff --git a/src/main/java/cz/cvut/kbss/termit/rest/handler/RestExceptionHandler.java b/src/main/java/cz/cvut/kbss/termit/rest/handler/RestExceptionHandler.java index b28baa022..5f26432bb 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/handler/RestExceptionHandler.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/handler/RestExceptionHandler.java @@ -17,6 +17,7 @@ */ package cz.cvut.kbss.termit.rest.handler; +import cz.cvut.kbss.jopa.exceptions.EntityNotFoundException; import cz.cvut.kbss.jopa.exceptions.OWLPersistenceException; import cz.cvut.kbss.jsonld.exception.JsonLdException; import cz.cvut.kbss.termit.exception.AnnotationGenerationException; @@ -112,6 +113,11 @@ public ResponseEntity usernameNotFound(HttpServletRequest request, Us return new ResponseEntity<>(errorInfo(request, e), HttpStatus.NOT_FOUND); } + @ExceptionHandler(EntityNotFoundException.class) + public ResponseEntity entityNotFoundException(HttpServletRequest request, EntityNotFoundException e) { + logException(e, request); + return new ResponseEntity<>(errorInfo(request, e), HttpStatus.NOT_FOUND); + } @ExceptionHandler(AuthorizationException.class) public ResponseEntity authorizationException(HttpServletRequest request, AuthorizationException e) { diff --git a/src/main/java/cz/cvut/kbss/termit/rest/readonly/ReadOnlyTermController.java b/src/main/java/cz/cvut/kbss/termit/rest/readonly/ReadOnlyTermController.java index 56c37fc7e..75c0cfe9b 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/readonly/ReadOnlyTermController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/readonly/ReadOnlyTermController.java @@ -232,7 +232,7 @@ public List getComments( @Parameter(description = "Datetime (ISO-formatted) of the latest comment to retrieve. Defaults to now.") @RequestParam(name = "to", required = false) Optional to) { final URI termUri = getTermUri(localName, termLocalName, namespace); - return termService.getComments(termService.getRequiredReference(termUri), + return termService.getComments(termService.getReference(termUri), from.map(RestUtils::parseTimestamp).orElse(Constants.EPOCH_TIMESTAMP), to.map(RestUtils::parseTimestamp).orElse(Utils.timestamp())); } @@ -257,7 +257,7 @@ public List getDefinitionallyRelatedTermsOf( example = TermController.ApiDoc.ID_NAMESPACE_EXAMPLE) @RequestParam(name = Constants.QueryParams.NAMESPACE, required = false) Optional namespace) { final URI termUri = getTermUri(localName, termLocalName, namespace); - return termService.getDefinitionallyRelatedOf(termService.getRequiredReference(termUri)); + return termService.getDefinitionallyRelatedOf(termService.getReference(termUri)); } @Operation( @@ -280,7 +280,7 @@ public List getDefinitionallyRelatedTermsTargeting( example = TermController.ApiDoc.ID_NAMESPACE_EXAMPLE) @RequestParam(name = Constants.QueryParams.NAMESPACE, required = false) Optional namespace) { final URI termUri = getTermUri(localName, termLocalName, namespace); - return termService.getDefinitionallyRelatedTargeting(termService.getRequiredReference(termUri)); + return termService.getDefinitionallyRelatedTargeting(termService.getReference(termUri)); } @Operation(description = "Gets a list of comments on the term with the specified identifier.") @@ -304,7 +304,7 @@ public List getComments( example = ApiDocConstants.DATETIME_EXAMPLE) @RequestParam(name = "to", required = false) Optional to) { final URI termUri = idResolver.resolveIdentifier(namespace, localName); - return termService.getComments(termService.getRequiredReference(termUri), + return termService.getComments(termService.getReference(termUri), from.map(RestUtils::parseTimestamp).orElse(Constants.EPOCH_TIMESTAMP), to.map(RestUtils::parseTimestamp).orElse(Utils.timestamp())); } diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/AccessControlListService.java b/src/main/java/cz/cvut/kbss/termit/service/business/AccessControlListService.java index 54073421a..783b54a33 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/AccessControlListService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/AccessControlListService.java @@ -52,7 +52,7 @@ public interface AccessControlListService { * @return Reference to a matching ACL * @throws cz.cvut.kbss.termit.exception.NotFoundException If no matching ACL exists */ - AccessControlList getRequiredReference(URI id); + AccessControlList getReference(URI id); /** * Finds an {@link AccessControlList} guarding access to the specified subject. diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/ResourceService.java b/src/main/java/cz/cvut/kbss/termit/service/business/ResourceService.java index 1a11ba6d7..824892e4c 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/ResourceService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/ResourceService.java @@ -108,7 +108,7 @@ public void remove(Resource toRemove) { throw new AssetRemovalException("Cannot remove non-empty document " + toRemove.getLabel() + "!"); } // We need the reference managed, so that its name is available to document manager - final Resource actualToRemove = getRequiredReference(toRemove.getUri()); + final Resource actualToRemove = getReference(toRemove.getUri()); documentManager.remove(actualToRemove); repositoryService.remove(actualToRemove); } @@ -224,12 +224,12 @@ public void addFileToDocument(Resource document, File file) { } doc.addFile(file); if (doc.getVocabulary() != null) { - final Vocabulary vocabulary = vocabularyService.getRequiredReference(doc.getVocabulary()); + final Vocabulary vocabulary = vocabularyService.getReference(doc.getVocabulary()); repositoryService.persist(file, vocabulary); } else { repositoryService.persist(file); } - if (getReference(document.getUri()).isEmpty()) { + if (!repositoryService.exists(document.getUri())) { repositoryService.persist(document); } else { update(doc); @@ -251,7 +251,7 @@ public void removeFile(File file) { throw new InvalidParameterException("File was not attached to a document."); } else { doc.removeFile(file); - if (repositoryService.getReference(doc.getUri()).isPresent()) { + if (repositoryService.find(doc.getUri()).isPresent()) { update(doc); } } @@ -292,7 +292,7 @@ public void runTextAnalysis(Resource resource, Set vocabularies) { private Set includeImportedVocabularies(Set providedVocabularies) { final Set result = new HashSet<>(providedVocabularies); providedVocabularies.forEach(uri -> { - final Vocabulary ref = vocabularyService.getRequiredReference(uri); + final Vocabulary ref = vocabularyService.getReference(uri); result.addAll(vocabularyService.getTransitivelyImportedVocabularies(ref)); }); return result; @@ -314,14 +314,10 @@ public Resource findRequired(URI id) { return repositoryService.findRequired(id); } - public Optional getReference(URI id) { + public Resource getReference(URI id) { return repositoryService.getReference(id); } - public Resource getRequiredReference(URI id) { - return repositoryService.getRequiredReference(id); - } - @Transactional @PreAuthorize("@resourceAuthorizationService.canModify(#instance)") public Resource update(Resource instance) { diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/RudService.java b/src/main/java/cz/cvut/kbss/termit/service/business/RudService.java index 7af6661e5..ecbb4e1eb 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/RudService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/RudService.java @@ -50,16 +50,7 @@ public interface RudService { * @param id Item identifier * @return Matching item reference wrapped in an {@code Optional} */ - Optional getReference(URI id); - - /** - * Gets a reference to an item with the specified identifier (with empty attribute values). - * - * @param id Item identifier - * @return Matching item reference - * @throws cz.cvut.kbss.termit.exception.NotFoundException When no matching item is found - */ - T getRequiredReference(URI id); + T getReference(URI id); /** * Updates the specified item. diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/TermOccurrenceService.java b/src/main/java/cz/cvut/kbss/termit/service/business/TermOccurrenceService.java index f391608ea..5f40caace 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/TermOccurrenceService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/TermOccurrenceService.java @@ -26,17 +26,6 @@ */ public interface TermOccurrenceService { - /** - * Gets a reference to a {@link TermOccurrence} with the specified identifier. - *

- * The returned instance may be empty apart from its identifier. - * - * @param id Term occurrence identifier - * @return Matching term occurrence - * @throws cz.cvut.kbss.termit.exception.NotFoundException If there is no such term occurrence - */ - TermOccurrence getRequiredReference(URI id); - /** * Persists the specified term occurrence. * diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java b/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java index 073bf0e78..1a0fa5542 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java @@ -263,8 +263,8 @@ public Vocabulary findVocabularyRequired(URI id) { * @throws NotFoundException When vocabulary with the specified identifier does not exist */ @PostAuthorize("@vocabularyAuthorizationService.canRead(returnObject)") - public Vocabulary getRequiredVocabularyReference(URI id) { - return vocabularyService.getRequiredReference(id); + public Vocabulary getVocabularyReference(URI id) { + return vocabularyService.getReference(id); } /** @@ -303,30 +303,16 @@ public Term findRequired(URI id) { /** * Gets a reference to a Term with the specified identifier. *

- * Note that this method is not protected by ACL-based authorization and should thus not be used in without some + * Note that this method is not protected by ACL-based authorization and should thus not be used without some * other type of authorization. * * @param id Term identifier * @return Matching Term reference wrapped in an {@code Optional} */ - public Optional getReference(URI id) { + public Term getReference(URI id) { return repositoryService.getReference(id); } - /** - * Gets a reference to a Term with the specified identifier. - *

- * Note that this method is not protected by ACL-based authorization and should thus not be used in without some - * other type of authorization. - * - * @param id Term identifier - * @return Matching term reference - * @throws NotFoundException When no matching term is found - */ - public Term getRequiredReference(URI id) { - return repositoryService.getRequiredReference(id); - } - /** * Gets child terms of the specified parent term. * @@ -400,7 +386,7 @@ public void persistChild(Term child, Term parent) { languageService.getInitialTermState().ifPresent(is -> child.setState(is.getUri())); repositoryService.addChildTerm(child, parent); analyzeTermDefinition(child, parent.getVocabulary()); - vocabularyService.runTextAnalysisOnAllTerms(getRequiredVocabularyReference(parent.getVocabulary())); + vocabularyService.runTextAnalysisOnAllTerms(getVocabularyReference(parent.getVocabulary())); } /** @@ -421,7 +407,7 @@ public Term update(Term term) { analyzeTermDefinition(term, original.getVocabulary()); } if (!Objects.equals(original.getLabel(), term.getLabel())) { - vocabularyService.runTextAnalysisOnAllTerms(getRequiredVocabularyReference(original.getVocabulary())); + vocabularyService.runTextAnalysisOnAllTerms(getVocabularyReference(original.getVocabulary())); } return result; } diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/UserService.java b/src/main/java/cz/cvut/kbss/termit/service/business/UserService.java index 1d1808e4e..b947cfb2e 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/UserService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/UserService.java @@ -32,6 +32,7 @@ import cz.cvut.kbss.termit.service.security.SecurityUtils; import cz.cvut.kbss.termit.util.Utils; import cz.cvut.kbss.termit.util.Vocabulary; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -110,8 +111,8 @@ public UserAccount findRequired(URI id) { * @return Reference to the matching user account * @throws NotFoundException When no matching account is found */ - public UserAccount getRequiredReference(URI id) { - return repositoryService.getRequiredReference(id); + public UserAccount getReference(URI id) { + return repositoryService.getReference(id); } /** @@ -168,6 +169,19 @@ public void persist(UserAccount account) { public void updateCurrent(UserUpdateDto update) { LOG.trace("Updating current user account."); Objects.requireNonNull(update); + UserAccount currentUser = getCurrentUser(update); + if (!Objects.equals(currentUser.getTypes(), update.getTypes())) { + throw new ValidationException( + "User " + securityUtils.getCurrentUser() + " attempted to update their role."); + } + if (update.getPassword() != null) { + securityUtils.verifyCurrentUserPassword(update.getOriginalPassword()); + } + repositoryService.update(update.asUserAccount()); + } + + @NotNull + private UserAccount getCurrentUser(UserUpdateDto update) { UserAccount currentUser = securityUtils.getCurrentUser(); if (!currentUser.getUri().equals(update.getUri())) { @@ -178,14 +192,7 @@ public void updateCurrent(UserUpdateDto update) { throw new ValidationException( "User " + securityUtils.getCurrentUser() + " attempted to update their username."); } - if (!Objects.equals(currentUser.getTypes(), update.getTypes())) { - throw new ValidationException( - "User " + securityUtils.getCurrentUser() + " attempted to update their role."); - } - if (update.getPassword() != null) { - securityUtils.verifyCurrentUserPassword(update.getOriginalPassword()); - } - repositoryService.update(update.asUserAccount()); + return currentUser; } /** diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/VocabularyService.java b/src/main/java/cz/cvut/kbss/termit/service/business/VocabularyService.java index ac55ce39a..e0374c4f8 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/VocabularyService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/VocabularyService.java @@ -137,16 +137,10 @@ public Vocabulary findRequired(URI id) { @Override @PostAuthorize("@vocabularyAuthorizationService.canRead(returnObject)") - public Optional getReference(URI id) { + public Vocabulary getReference(URI id) { return repositoryService.getReference(id); } - @Override - @PostAuthorize("@vocabularyAuthorizationService.canRead(returnObject)") - public Vocabulary getRequiredReference(URI id) { - return repositoryService.getRequiredReference(id); - } - @Override @Transactional @PreAuthorize("@vocabularyAuthorizationService.canCreate()") @@ -255,7 +249,7 @@ public void runTextAnalysisOnAllTerms(Vocabulary vocabulary) { SnapshotProvider.verifySnapshotNotModified(vocabulary); final List allTerms = termService.findAll(vocabulary); getTransitivelyImportedVocabularies(vocabulary).forEach( - importedVocabulary -> allTerms.addAll(termService.findAll(getRequiredReference(importedVocabulary)))); + importedVocabulary -> allTerms.addAll(termService.findAll(getReference(importedVocabulary)))); final Map termsToContexts = new HashMap<>(allTerms.size()); allTerms.forEach(t -> termsToContexts.put(t, contextMapper.getVocabularyContext(t.getVocabulary()))); termService.asyncAnalyzeTermDefinitions(termsToContexts); diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermService.java b/src/main/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermService.java index 1e350ddc4..86d3782c6 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermService.java @@ -113,8 +113,8 @@ public List getComments(Term term, Instant from, Instant to) { return termService.getComments(term, from, to); } - public Term getRequiredReference(URI uri) { - return termService.getRequiredReference(uri); + public Term getReference(URI uri) { + return termService.getReference(uri); } /** 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 ee983b752..a5015182d 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 @@ -103,10 +103,14 @@ public Optional find(URI id) { * for the loaded instance. * * @param id Identifier of the object to load - * @return {@link Optional} with the loaded reference or an empty one + * @return Entity reference + * @throws NotFoundException If no matching instance is found */ - public Optional getReference(URI id) { - return getPrimaryDao().getReference(id); + public T getReference(URI id) { + if (exists(id)) { + return getPrimaryDao().getReference(id); + } + throw NotFoundException.create(resolveGenericType().getSimpleName(), id); } /** @@ -124,25 +128,6 @@ public T findRequired(URI id) { return find(id).orElseThrow(() -> NotFoundException.create(resolveGenericType().getSimpleName(), id)); } - /** - * Gets a reference to an object wih the specified identifier. - *

- * In comparison to {@link #getReference(URI)}, this method guarantees to return a matching instance. If no such - * object is found, a {@link NotFoundException} is thrown. - *

- * Note that all attributes of the reference are loaded lazily and the corresponding persistence context must be - * still open to load them. - *

- * Also note that, in contrast to {@link #find(URI)}, this method does not invoke {@link #postLoad(HasIdentifier)} - * for the loaded instance. - * - * @param id Identifier of the object to load - * @return {@link Optional} with the loaded reference or an empty one - */ - public T getRequiredReference(URI id) { - return getReference(id).orElseThrow(() -> NotFoundException.create(resolveGenericType().getSimpleName(), id)); - } - /** * Resolves the actual generic type of the implementation of {@link BaseRepositoryService}. * diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/RepositoryAccessControlListService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/RepositoryAccessControlListService.java index f52f9ced2..e05d05df2 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/RepositoryAccessControlListService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/RepositoryAccessControlListService.java @@ -82,7 +82,7 @@ public AccessControlList findRequired(URI id) { } @Override - public AccessControlList getRequiredReference(URI id) { + public AccessControlList getReference(URI id) { return dao.getReference(id).orElseThrow(() -> NotFoundException.create(AccessControlList.class, id)); } diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/TermOccurrenceRepositoryService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/TermOccurrenceRepositoryService.java index 20c19851c..88940766e 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/TermOccurrenceRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/TermOccurrenceRepositoryService.java @@ -58,11 +58,6 @@ public TermOccurrenceRepositoryService(TermOccurrenceDao termOccurrenceDao, Term this.resourceService = resourceService; } - @Override - public TermOccurrence getRequiredReference(URI id) { - return termOccurrenceDao.getReference(id).orElseThrow(() -> NotFoundException.create(TermOccurrence.class, id)); - } - @Transactional @Override public void persist(TermOccurrence occurrence) { @@ -118,7 +113,7 @@ public void approve(URI occurrenceId) { public void remove(URI occurrenceId) { Objects.requireNonNull(occurrenceId); LOG.trace("Removing term occurrence {}.", occurrenceId); - termOccurrenceDao.getReference(occurrenceId).ifPresent(termOccurrenceDao::remove); + termOccurrenceDao.find(occurrenceId).ifPresent(termOccurrenceDao::remove); } /** diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java index f9b09a1b7..23d5e2171 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java @@ -126,7 +126,7 @@ private void pruneEmptyTranslations(Term instance) { @Override protected void postUpdate(@NotNull Term instance) { - final Vocabulary vocabulary = vocabularyService.getRequiredReference(instance.getVocabulary()); + final Vocabulary vocabulary = vocabularyService.getReference(instance.getVocabulary()); if (instance.hasParentInSameVocabulary()) { vocabulary.getGlossary().removeRootTerm(instance); } else { @@ -170,7 +170,7 @@ private URI generateIdentifier(URI vocabularyUri, MultilingualString multilingua private void addTermAsRootToGlossary(Term instance, URI vocabularyIri) { // Load vocabulary so that it is managed and changes to it (resp. the glossary) are persisted on commit - final Vocabulary toUpdate = vocabularyService.getRequiredReference(vocabularyIri); + final Vocabulary toUpdate = vocabularyService.getReference(vocabularyIri); instance.setGlossary(toUpdate.getGlossary().getUri()); toUpdate.getGlossary().addRootTerm(instance); } @@ -185,7 +185,7 @@ public void addChildTerm(Term instance, Term parentTerm) { instance.getVocabulary() != null ? instance.getVocabulary() : parentTerm.getVocabulary(); prepareTermForPersist(instance, vocabularyIri); - final Vocabulary vocabulary = vocabularyService.getRequiredReference(vocabularyIri); + final Vocabulary vocabulary = vocabularyService.getReference(vocabularyIri); instance.setGlossary(vocabulary.getGlossary().getUri()); instance.addParentTerm(parentTerm); instance.splitExternalAndInternalParents(); diff --git a/src/test/java/cz/cvut/kbss/termit/environment/Transaction.java b/src/test/java/cz/cvut/kbss/termit/environment/Transaction.java index 1c842871b..3ccb06545 100644 --- a/src/test/java/cz/cvut/kbss/termit/environment/Transaction.java +++ b/src/test/java/cz/cvut/kbss/termit/environment/Transaction.java @@ -17,6 +17,7 @@ */ package cz.cvut.kbss.termit.environment; +import org.jetbrains.annotations.NotNull; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; @@ -47,7 +48,26 @@ public static void execute(PlatformTransactionManager txManager, Runnable proced new TransactionTemplate(txManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) { + protected void doInTransactionWithoutResult(@NotNull TransactionStatus transactionStatus) { + procedure.run(); + } + }); + } + + /** + * Helper method for executing the specified portion of code in a read-only transaction. + *

+ * This method allows executing transactional behavior in a read-only mode. + * + * @param txManager Transaction manager to use to run the transactional code + * @param procedure Code to execute + */ + public static void executeReadOnly(PlatformTransactionManager txManager, Runnable procedure) { + final TransactionTemplate transaction = new TransactionTemplate(txManager); + transaction.setReadOnly(true); + new TransactionTemplate(txManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@NotNull TransactionStatus transactionStatus) { procedure.run(); } }); diff --git a/src/test/java/cz/cvut/kbss/termit/environment/TransactionalTestRunner.java b/src/test/java/cz/cvut/kbss/termit/environment/TransactionalTestRunner.java index 1427929a6..2428ca354 100644 --- a/src/test/java/cz/cvut/kbss/termit/environment/TransactionalTestRunner.java +++ b/src/test/java/cz/cvut/kbss/termit/environment/TransactionalTestRunner.java @@ -30,6 +30,10 @@ protected void transactional(Runnable procedure) { Transaction.execute(txManager, procedure); } + protected void readOnlyTransactional(Runnable procedure) { + Transaction.executeReadOnly(txManager, procedure); + } + protected void enableRdfsInference(EntityManager em) { transactional(() -> Environment.addModelStructureForRdfsInference(em)); } diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTest.java index f677393f3..edf377c6e 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTest.java @@ -34,8 +34,15 @@ import java.util.stream.IntStream; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; -import static org.junit.jupiter.api.Assertions.*; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; class BaseDaoTest extends BaseDaoTestRunner { @@ -59,7 +66,7 @@ void findAllRetrievesAllExistingInstances() { }).collect(Collectors.toList()); transactional(() -> sut.persist(terms)); final List result = sut.findAll(); - assertThat(result, hasItems(terms.toArray(new Term[] {}))); + assertThat(result, hasItems(terms.toArray(new Term[]{}))); } @Test @@ -151,7 +158,7 @@ void exceptionDuringCollectionPersistIsWrappedInPersistenceException() { transactional(() -> sut.persist(terms)); final PersistenceException e = assertThrows(PersistenceException.class, - () -> transactional(() -> sut.persist(terms))); + () -> transactional(() -> sut.persist(terms))); assertThat(e.getCause(), is(instanceOf(OWLPersistenceException.class))); } @@ -159,16 +166,12 @@ void exceptionDuringCollectionPersistIsWrappedInPersistenceException() { void getReferenceRetrievesReferenceToMatchingInstance() { final Term term = Generator.generateTermWithId(); transactional(() -> sut.persist(term)); - final Optional result = sut.getReference(term.getUri()); - assertTrue(result.isPresent()); - assertEquals(term.getUri(), result.get().getUri()); - } - - @Test - void getReferenceReturnsEmptyOptionalWhenNoMatchingInstanceExists() { - final Optional result = sut.getReference(Generator.generateUri()); - assertNotNull(result); - assertFalse(result.isPresent()); + readOnlyTransactional(() -> { + final Term result = sut.getReference(term.getUri()); + assertNotNull(result); + // This will trigger state loading + assertEquals(term, result); + }); } @Test 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 4a96ae7c4..66bf8473a 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 @@ -353,7 +353,7 @@ void removeFileUpdatesParentDocumentInVocabularyContext() { }); transactional(() -> { - final Resource toRemove = sut.getReference(file.getUri()).get(); + final Resource toRemove = sut.getReference(file.getUri()); sut.remove(toRemove); }); diff --git a/src/test/java/cz/cvut/kbss/termit/rest/ResourceControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/ResourceControllerTest.java index c6aa208cf..a9ef5cae9 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/ResourceControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/ResourceControllerTest.java @@ -226,7 +226,7 @@ void getFilesLoadsFilesFromDocumentWithSpecifiedIdentifier() throws Exception { document.setUri(RESOURCE_URI); final File fOne = generateFile(); document.addFile(fOne); - when(resourceServiceMock.getRequiredReference(document.getUri())).thenReturn(document); + when(resourceServiceMock.getReference(document.getUri())).thenReturn(document); when(resourceServiceMock.getFiles(document)).thenReturn(new ArrayList<>(document.getFiles())); when(identifierResolverMock.resolveIdentifier(RESOURCE_NAMESPACE, RESOURCE_NAME)).thenReturn(document.getUri()); @@ -245,7 +245,7 @@ void getFilesReturnsConflictWhenRequestedResourceIsNotDocument() throws Exceptio resource.setUri(RESOURCE_URI); resource.setLabel(RESOURCE_NAME); when(identifierResolverMock.resolveIdentifier(RESOURCE_NAMESPACE, RESOURCE_NAME)).thenReturn(RESOURCE_URI); - when(resourceServiceMock.getRequiredReference(RESOURCE_URI)).thenReturn(resource); + when(resourceServiceMock.getReference(RESOURCE_URI)).thenReturn(resource); when(resourceServiceMock.getFiles(resource)).thenThrow(UnsupportedAssetOperationException.class); mockMvc.perform(get(PATH + "/" + RESOURCE_NAME + "/files").param(QueryParams.NAMESPACE, RESOURCE_NAMESPACE)) .andExpect(status().isConflict()); @@ -395,7 +395,7 @@ void getHistoryReturnsListOfChangeRecordsForSpecifiedVocabulary() throws Excepti final Resource resource = Generator.generateResourceWithId(); resource.setUri(RESOURCE_URI); when(identifierResolverMock.resolveIdentifier(RESOURCE_NAMESPACE, RESOURCE_NAME)).thenReturn(resource.getUri()); - when(resourceServiceMock.getRequiredReference(RESOURCE_URI)).thenReturn(resource); + when(resourceServiceMock.getReference(RESOURCE_URI)).thenReturn(resource); final List records = Collections.singletonList(Generator.generatePersistChange(resource)); when(resourceServiceMock.getChanges(resource)).thenReturn(records); diff --git a/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java index 91b462006..3133f713c 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/TermControllerTest.java @@ -147,7 +147,7 @@ void termsExistCheckReturnOkIfTermLabelExistsInVocabulary() throws Exception { final String language = "en"; final URI vocabularyUri = URI.create(namespace + VOCABULARY_NAME); when(idResolverMock.resolveIdentifier(namespace, VOCABULARY_NAME)).thenReturn(vocabularyUri); - when(termServiceMock.getRequiredVocabularyReference(vocabularyUri)).thenReturn(vocabulary); + when(termServiceMock.getVocabularyReference(vocabularyUri)).thenReturn(vocabulary); when(termServiceMock.existsInVocabulary(any(), any(), any())).thenReturn(true); mockMvc.perform( head(PATH + VOCABULARY_NAME + "/terms") @@ -165,7 +165,7 @@ void termsExistCheckReturn404IfTermLabelDoesNotExistInVocabulary() throws Except final String language = "en"; final URI vocabularyUri = URI.create(namespace + VOCABULARY_NAME); when(idResolverMock.resolveIdentifier(namespace, VOCABULARY_NAME)).thenReturn(vocabularyUri); - when(termServiceMock.getRequiredVocabularyReference(vocabularyUri)).thenReturn(vocabulary); + when(termServiceMock.getVocabularyReference(vocabularyUri)).thenReturn(vocabulary); when(termServiceMock.existsInVocabulary(any(), any(), any())).thenReturn(false); mockMvc.perform( head(PATH + VOCABULARY_NAME + "/terms") @@ -1042,7 +1042,7 @@ void getAllTermsCallsServiceWithSearchString() throws Exception { void checkTermsRetrievesNumberOfTermsInVocabularyWithSpecifiedIdentifier() throws Exception { when(idResolverMock.resolveIdentifier(config.getNamespace().getVocabulary(), VOCABULARY_NAME)) .thenReturn(URI.create(VOCABULARY_URI)); - when(termServiceMock.getRequiredVocabularyReference(vocabulary.getUri())).thenReturn(vocabulary); + when(termServiceMock.getVocabularyReference(vocabulary.getUri())).thenReturn(vocabulary); final Integer termCount = Generator.randomInt(0, 200); when(termServiceMock.getTermCount(vocabulary)).thenReturn(termCount); diff --git a/src/test/java/cz/cvut/kbss/termit/rest/UserControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/UserControllerTest.java index 62a261d88..b23e3ccf4 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/UserControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/UserControllerTest.java @@ -171,7 +171,7 @@ void changeRoleUsesProvidedNamespaceToResolveUserUri() throws Exception { void getManagedAssetsRetrievesManagedAssetsForUserWithSpecifiedUri() throws Exception { final String namespace = Vocabulary.s_c_uzivatel_termitu + "/"; when(idResolverMock.resolveIdentifier(any(), any())).thenReturn(user.getUri()); - when(userService.getRequiredReference(user.getUri())).thenReturn(user); + when(userService.getReference(user.getUri())).thenReturn(user); final List resources = Collections.singletonList( new RdfsResource(Generator.generateUri(), MultilingualString.create("Test term", Environment.LANGUAGE), null, diff --git a/src/test/java/cz/cvut/kbss/termit/rest/UserGroupControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/UserGroupControllerTest.java index 219873b6e..b0f7740d1 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/UserGroupControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/UserGroupControllerTest.java @@ -80,7 +80,7 @@ void createReturnsCreatedResponseWithLocationHeader() throws Exception { void removeRemovesSpecifiedGroupViaService() throws Exception { final UserGroup toRemove = Generator.generateUserGroup(); final String fragment = IdentifierResolver.extractIdentifierFragment(toRemove.getUri()); - when(groupService.getRequiredReference(toRemove.getUri())).thenReturn(toRemove); + when(groupService.getReference(toRemove.getUri())).thenReturn(toRemove); mockMvc.perform(delete(UserGroupController.PATH + "/" + fragment)).andExpect(status().isNoContent()); verify(groupService).remove(toRemove); } diff --git a/src/test/java/cz/cvut/kbss/termit/rest/VocabularyControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/VocabularyControllerTest.java index 2dbfcb2de..afc335516 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/VocabularyControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/VocabularyControllerTest.java @@ -352,7 +352,7 @@ void getTransitiveImportsReturnsCollectionOfImportIdentifiersRetrievedFromServic .thenReturn(VOCABULARY_URI); final Set imports = IntStream.range(0, 5).mapToObj(i -> Generator.generateUri()) .collect(Collectors.toSet()); - when(serviceMock.getRequiredReference(VOCABULARY_URI)).thenReturn(vocabulary); + when(serviceMock.getReference(VOCABULARY_URI)).thenReturn(vocabulary); when(serviceMock.getTransitivelyImportedVocabularies(vocabulary)).thenReturn(imports); final MvcResult mvcResult = @@ -361,7 +361,7 @@ void getTransitiveImportsReturnsCollectionOfImportIdentifiersRetrievedFromServic final Set result = readValue(mvcResult, new TypeReference>() { }); assertEquals(imports, result); - verify(serviceMock).getRequiredReference(VOCABULARY_URI); + verify(serviceMock).getReference(VOCABULARY_URI); verify(serviceMock).getTransitivelyImportedVocabularies(vocabulary); } @@ -379,7 +379,7 @@ void getTransitiveImportsReturnsEmptyCollectionWhenNoImportsAreFoundForVocabular }); assertNotNull(result); assertTrue(result.isEmpty()); - verify(serviceMock).getRequiredReference(VOCABULARY_URI); + verify(serviceMock).getReference(VOCABULARY_URI); verify(serviceMock).getTransitivelyImportedVocabularies(vocabulary); } @@ -470,7 +470,7 @@ private Vocabulary generateVocabularyAndInitReferenceResolution() { vocabulary.setUri(VOCABULARY_URI); when(idResolverMock.resolveIdentifier(configMock.getNamespace().getVocabulary(), FRAGMENT)) .thenReturn(VOCABULARY_URI); - when(serviceMock.getRequiredReference(VOCABULARY_URI)).thenReturn(vocabulary); + when(serviceMock.getReference(VOCABULARY_URI)).thenReturn(vocabulary); return vocabulary; } diff --git a/src/test/java/cz/cvut/kbss/termit/rest/readonly/ReadOnlyTermControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/readonly/ReadOnlyTermControllerTest.java index 6d34885de..2b8be7ed8 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/readonly/ReadOnlyTermControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/readonly/ReadOnlyTermControllerTest.java @@ -277,7 +277,7 @@ void getCommentsRetrievesCommentsForSpecifiedTermUsingDefaultTimeInterval() thro final URI termUri = initTermUriResolution(); final Term term = Generator.generateTerm(); term.setUri(termUri); - when(termService.getRequiredReference(term.getUri())).thenReturn(term); + when(termService.getReference(term.getUri())).thenReturn(term); final List comments = generateComments(term); when(termService.getComments(eq(term), any(Instant.class), any(Instant.class))).thenReturn(comments); @@ -296,7 +296,7 @@ void getCommentsRetrievesCommentsInSpecifiedTimeInterval() throws Exception { final URI termUri = initTermUriResolution(); final Term term = Generator.generateTerm(); term.setUri(termUri); - when(termService.getRequiredReference(term.getUri())).thenReturn(term); + when(termService.getReference(term.getUri())).thenReturn(term); final List comments = generateComments(term); when(termService.getComments(eq(term), any(Instant.class), any(Instant.class))).thenReturn(comments); final Instant from = Utils.timestamp().minus(Generator.randomInt(50, 100), ChronoUnit.DAYS); @@ -317,7 +317,7 @@ void getDefinitionallyRelatedOfRetrievesDefinitionalOccurrencesOfSpecifiedTerm() final URI termUri = initTermUriResolution(); final Term term = Generator.generateTerm(); term.setUri(termUri); - when(termService.getRequiredReference(termUri)).thenReturn(term); + when(termService.getReference(termUri)).thenReturn(term); final List occurrences = generateOccurrences(term, true); when(termService.getDefinitionallyRelatedOf(term)).thenReturn(occurrences); @@ -327,7 +327,7 @@ void getDefinitionallyRelatedOfRetrievesDefinitionalOccurrencesOfSpecifiedTerm() final List result = readValue(mvcResult, new TypeReference>() { }); assertThat(result, containsSameEntities(occurrences)); - verify(termService).getRequiredReference(termUri); + verify(termService).getReference(termUri); verify(termService).getDefinitionallyRelatedOf(term); } @@ -348,7 +348,7 @@ void getDefinitionallyRelatedTargetingRetrievesDefinitionalOccurrencesTargetingS final URI termUri = initTermUriResolution(); final Term term = Generator.generateTerm(); term.setUri(termUri); - when(termService.getRequiredReference(termUri)).thenReturn(term); + when(termService.getReference(termUri)).thenReturn(term); final List occurrences = generateOccurrences(term, false); when(termService.getDefinitionallyRelatedTargeting(term)).thenReturn(occurrences); @@ -358,7 +358,7 @@ void getDefinitionallyRelatedTargetingRetrievesDefinitionalOccurrencesTargetingS final List result = readValue(mvcResult, new TypeReference>() { }); assertThat(result, containsSameEntities(occurrences)); - verify(termService).getRequiredReference(termUri); + verify(termService).getReference(termUri); verify(termService).getDefinitionallyRelatedTargeting(term); } diff --git a/src/test/java/cz/cvut/kbss/termit/service/business/ResourceServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/business/ResourceServiceTest.java index 9c02130a7..b98434ce4 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/business/ResourceServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/business/ResourceServiceTest.java @@ -105,7 +105,7 @@ void updateUpdatesResourceViaRepositoryService() { @Test void removeRemovesResourceViaRepositoryService() { final Resource resource = Generator.generateResourceWithId(); - when(resourceRepositoryService.getRequiredReference(resource.getUri())).thenReturn(resource); + when(resourceRepositoryService.getReference(resource.getUri())).thenReturn(resource); sut.remove(resource); verify(resourceRepositoryService).remove(resource); } @@ -117,7 +117,7 @@ void removeEnsuresAttributesForDocumentManagerArePresent() { toRemove.setUri(Generator.generateUri()); final Resource resource = Generator.generateResource(); resource.setUri(toRemove.getUri()); - when(resourceRepositoryService.getRequiredReference(resource.getUri())).thenReturn(resource); + when(resourceRepositoryService.getReference(resource.getUri())).thenReturn(resource); sut.remove(resource); verify(resourceRepositoryService).remove(resource); verify(documentManager).remove(resource); @@ -216,7 +216,7 @@ void runTextAnalysisInvokesAnalysisAlsoWithImportedVocabulariesOfVocabularyRElat final Vocabulary vocabulary = Generator.generateVocabularyWithId(); file.getDocument().setVocabulary(vocabulary.getUri()); final Set imported = new HashSet<>(Arrays.asList(Generator.generateUri(), Generator.generateUri())); - when(vocabularyService.getRequiredReference(vocabulary.getUri())).thenReturn(vocabulary); + when(vocabularyService.getReference(vocabulary.getUri())).thenReturn(vocabulary); when(vocabularyService.getTransitivelyImportedVocabularies(vocabulary)).thenReturn(imported); sut.runTextAnalysis(file, Collections.emptySet()); @@ -233,9 +233,9 @@ void runTextAnalysisInvokesAnalysisWithProvidedVocabulariesAndTheirImports() { final Set vOneImports = new HashSet<>(Arrays.asList(Generator.generateUri(), Generator.generateUri())); final Vocabulary vTwo = Generator.generateVocabularyWithId(); final Set vTwoImports = Collections.singleton(Generator.generateUri()); - when(vocabularyService.getRequiredReference(vOne.getUri())).thenReturn(vOne); + when(vocabularyService.getReference(vOne.getUri())).thenReturn(vOne); when(vocabularyService.getTransitivelyImportedVocabularies(vOne)).thenReturn(vOneImports); - when(vocabularyService.getRequiredReference(vTwo.getUri())).thenReturn(vTwo); + when(vocabularyService.getReference(vTwo.getUri())).thenReturn(vTwo); when(vocabularyService.getTransitivelyImportedVocabularies(vTwo)).thenReturn(vTwoImports); sut.runTextAnalysis(file, new HashSet<>(Arrays.asList(vOne.getUri(), vTwo.getUri()))); @@ -255,13 +255,6 @@ void getReferenceDelegatesCallToRepositoryService() { verify(resourceRepositoryService).getReference(uri); } - @Test - void getRequiredReferenceDelegatesCallToRepositoryService() { - final URI uri = Generator.generateUri(); - sut.getRequiredReference(uri); - verify(resourceRepositoryService).getRequiredReference(uri); - } - @Test void getFilesReturnsFilesFromDocument() { final Document doc = Generator.generateDocumentWithId(); @@ -324,11 +317,11 @@ void addFileToDocumentPersistsFileIntoVocabularyContextForDocumentWithVocabulary final Document doc = Generator.generateDocumentWithId(); doc.setVocabulary(vocabulary.getUri()); final File fOne = Generator.generateFileWithId("test.html"); - when(vocabularyService.getRequiredReference(vocabulary.getUri())).thenReturn(vocabulary); + when(vocabularyService.getReference(vocabulary.getUri())).thenReturn(vocabulary); sut.addFileToDocument(doc, fOne); verify(resourceRepositoryService).persist(fOne, vocabulary); - verify(vocabularyService).getRequiredReference(vocabulary.getUri()); + verify(vocabularyService).getReference(vocabulary.getUri()); } @Test @@ -337,11 +330,11 @@ void addFileToDocumentUpdatesDocumentInVocabularyContextForDocumentWithVocabular final Document doc = Generator.generateDocumentWithId(); doc.setVocabulary(vocabulary.getUri()); final File fOne = Generator.generateFileWithId("test.html"); - when(vocabularyService.getRequiredReference(vocabulary.getUri())).thenReturn(vocabulary); + when(vocabularyService.getReference(vocabulary.getUri())).thenReturn(vocabulary); sut.addFileToDocument(doc, fOne); verify(resourceRepositoryService).persist(doc); - verify(vocabularyService).getRequiredReference(vocabulary.getUri()); + verify(vocabularyService).getReference(vocabulary.getUri()); } @Test @@ -400,7 +393,7 @@ void hasContentReturnsFalseForNonFile() { @Test void removeRemovesAssociatedDiskContent() { final Resource resource = Generator.generateResourceWithId(); - when(resourceRepositoryService.getRequiredReference(resource.getUri())).thenReturn(resource); + when(resourceRepositoryService.getReference(resource.getUri())).thenReturn(resource); sut.remove(resource); verify(documentManager).remove(resource); } diff --git a/src/test/java/cz/cvut/kbss/termit/service/business/TermServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/business/TermServiceTest.java index a7d26dde4..cd1fed9b7 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/business/TermServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/business/TermServiceTest.java @@ -271,20 +271,10 @@ void findAllCallsFindAllInRepositoryService() { @Test void getReferenceRetrievesTermReferenceFromRepositoryService() { final Term t = Generator.generateTermWithId(); - when(termRepositoryService.getReference(t.getUri())).thenReturn(Optional.of(t)); - final Optional result = sut.getReference(t.getUri()); - assertTrue(result.isPresent()); - assertEquals(t, result.get()); - verify(termRepositoryService).getReference(t.getUri()); - } - - @Test - void getRequiredReferenceRetrievesTermReferenceFromRepositoryService() { - final Term t = Generator.generateTermWithId(); - when(termRepositoryService.getRequiredReference(t.getUri())).thenReturn(t); - final Term result = sut.getRequiredReference(t.getUri()); + when(termRepositoryService.getReference(t.getUri())).thenReturn(t); + final Term result = sut.getReference(t.getUri()); assertEquals(t, result); - verify(termRepositoryService).getRequiredReference(t.getUri()); + verify(termRepositoryService).getReference(t.getUri()); } @Test @@ -465,7 +455,7 @@ void persistChildInvokesTextAnalysisOnAllTermsInParentTermVocabulary() { final Term parent = generateTermWithId(); parent.setVocabulary(vocabulary.getUri()); final Term childToPersist = generateTermWithId(); - when(vocabularyService.getRequiredReference(vocabulary.getUri())).thenReturn(vocabulary); + when(vocabularyService.getReference(vocabulary.getUri())).thenReturn(vocabulary); when(vocabularyContextMapper.getVocabularyContext(vocabulary.getUri())).thenReturn(vocabulary.getUri()); sut.persistChild(childToPersist, parent); @@ -483,7 +473,7 @@ void updateInvokesTextAnalysisOnAllTermsInTermsVocabularyWhenLabelHasChanged() { update.setDescription(new MultilingualString(original.getDescription().getValue())); update.setVocabulary(vocabulary.getUri()); when(termRepositoryService.findRequired(original.getUri())).thenReturn(original); - when(vocabularyService.getRequiredReference(vocabulary.getUri())).thenReturn(vocabulary); + when(vocabularyService.getReference(vocabulary.getUri())).thenReturn(vocabulary); update.getLabel().set(Environment.LANGUAGE, "updatedLabel"); sut.update(update); diff --git a/src/test/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermServiceTest.java index dfc4626e5..2dd2eda9c 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/business/readonly/ReadOnlyTermServiceTest.java @@ -70,7 +70,7 @@ class ReadOnlyTermServiceTest { private ReadOnlyTermService sut; @Test - void getRequiredVocabularyReferenceRetrievesReferenceToVocabularyFromService() { + void getVocabularyReferenceRetrievesReferenceToVocabularyFromService() { final Vocabulary vocabulary = Generator.generateVocabularyWithId(); when(termService.findVocabularyRequired(any())).thenReturn(vocabulary); 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 9bbcbd4ca..2c9b4a07d 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 @@ -256,4 +256,19 @@ void findRequiredInvokesPostLoadOnLoadedInstance() { inOrder.verify(userAccountDaoMock).find(instance.getUri()); inOrder.verify(sut).postLoad(instance); } + + @Test + void getReferenceRetrievesReferenceFromDaoWhenInstanceExists() { + final UserAccount instance = Generator.generateUserAccountWithPassword(); + transactional(() -> em.persist(instance)); + final UserAccount result = sut.getReference(instance.getUri()); + assertNotNull(result); + assertEquals(instance.getUri(), result.getUri()); + } + + @Test + void getReferenceThrowsNotFoundExceptionWhenInstanceDoesNotExist() { + final URI id = Generator.generateUri(); + assertThrows(NotFoundException.class, () -> sut.getReference(id)); + } } diff --git a/src/test/java/cz/cvut/kbss/termit/service/repository/RepositoryAccessControlListServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/repository/RepositoryAccessControlListServiceTest.java index 492f4c4d2..a4532d325 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/repository/RepositoryAccessControlListServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/repository/RepositoryAccessControlListServiceTest.java @@ -138,11 +138,11 @@ void updateRecordLoadsTargetAccessControlListAndUpdatesSpecifiedRecords() { } @Test - void getRequiredReferenceThrowsNotFoundExceptionWhenMatchingAccessControlListIsNotFound() { + void getReferenceThrowsNotFoundExceptionWhenMatchingAccessControlListIsNotFound() { final URI uri = Generator.generateUri(); when(dao.getReference(uri)).thenReturn(Optional.empty()); - assertThrows(NotFoundException.class, () -> sut.getRequiredReference(uri)); + assertThrows(NotFoundException.class, () -> sut.getReference(uri)); verify(dao).getReference(uri); } From bc53544b681210fcf078737e5d251b28369982c3 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Thu, 11 Jul 2024 18:46:00 +0200 Subject: [PATCH 02/11] [GH-268] Remove RefreshLastModifiedAspect, rewrite related logic to events. --- .../aspect/RefreshLastModifiedAspect.java | 45 ------------------- .../termit/asset/provenance/ModifiesData.java | 6 +-- .../kbss/termit/persistence/dao/BaseDao.java | 24 ++++++++-- .../termit/persistence/dao/ResourceDao.java | 21 +++++---- .../termit/persistence/dao/VocabularyDao.java | 35 +++++++++------ .../termit/rest/VocabularyController.java | 6 +-- .../termit/persistence/dao/BaseDaoTest.java | 5 +++ 7 files changed, 64 insertions(+), 78 deletions(-) delete mode 100644 src/main/java/cz/cvut/kbss/termit/aspect/RefreshLastModifiedAspect.java diff --git a/src/main/java/cz/cvut/kbss/termit/aspect/RefreshLastModifiedAspect.java b/src/main/java/cz/cvut/kbss/termit/aspect/RefreshLastModifiedAspect.java deleted file mode 100644 index a977d083b..000000000 --- a/src/main/java/cz/cvut/kbss/termit/aspect/RefreshLastModifiedAspect.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * TermIt - * Copyright (C) 2023 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 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 . - */ -package cz.cvut.kbss.termit.aspect; - -import cz.cvut.kbss.termit.asset.provenance.SupportsLastModification; -import org.aspectj.lang.annotation.After; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Ensures corresponding last modified timestamp is refreshed when a data modifying operation is invoked for an asset. - */ -@Aspect -public class RefreshLastModifiedAspect { - - private static final Logger LOG = LoggerFactory.getLogger(RefreshLastModifiedAspect.class); - - @Pointcut(value = "@annotation(cz.cvut.kbss.termit.asset.provenance.ModifiesData) " + - "&& target(cz.cvut.kbss.termit.asset.provenance.SupportsLastModification)") - public void dataModificationOperation() { - } - - @After(value = "dataModificationOperation() && target(bean)", argNames = "bean") - public void refreshLastModified(SupportsLastModification bean) { - LOG.trace("Refreshing last modified timestamp on bean {}.", bean); - bean.refreshLastModified(); - } -} diff --git a/src/main/java/cz/cvut/kbss/termit/asset/provenance/ModifiesData.java b/src/main/java/cz/cvut/kbss/termit/asset/provenance/ModifiesData.java index c623a42d1..6cd707854 100644 --- a/src/main/java/cz/cvut/kbss/termit/asset/provenance/ModifiesData.java +++ b/src/main/java/cz/cvut/kbss/termit/asset/provenance/ModifiesData.java @@ -17,8 +17,6 @@ */ package cz.cvut.kbss.termit.asset.provenance; -import cz.cvut.kbss.termit.aspect.RefreshLastModifiedAspect; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -27,9 +25,7 @@ /** * Designates methods which modify data and should thus refresh last modified date on completion. *

- * This annotation should be used on methods of classes implementing {@link SupportsLastModification}. A corresponding - * aspect defined in {@link RefreshLastModifiedAspect} refreshes the last modified timestamp when a method modifying - * data is invoked. + * This annotation should be used on methods of classes implementing {@link SupportsLastModification}. */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseDao.java index 9ba16facf..a4e495cc1 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseDao.java @@ -21,9 +21,13 @@ import cz.cvut.kbss.jopa.model.descriptors.Descriptor; import cz.cvut.kbss.jopa.model.descriptors.EntityDescriptor; import cz.cvut.kbss.termit.asset.provenance.ModifiesData; +import cz.cvut.kbss.termit.event.RefreshLastModifiedEvent; import cz.cvut.kbss.termit.exception.PersistenceException; import cz.cvut.kbss.termit.model.util.EntityToOwlClassMapper; import cz.cvut.kbss.termit.model.util.HasIdentifier; +import org.jetbrains.annotations.NotNull; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; import java.net.URI; import java.util.Collection; @@ -34,13 +38,15 @@ /** * Base implementation of the generic DAO API. */ -public abstract class BaseDao implements GenericDao { +public abstract class BaseDao implements GenericDao, ApplicationEventPublisherAware { protected final Class type; protected final URI typeUri; protected final EntityManager em; + protected ApplicationEventPublisher eventPublisher; + protected BaseDao(Class type, EntityManager em) { this.type = type; this.typeUri = URI.create(EntityToOwlClassMapper.getOwlClassForEntity(type)); @@ -93,6 +99,7 @@ public void persist(T entity) { } catch (RuntimeException e) { throw new PersistenceException(e); } + eventPublisher.publishEvent(new RefreshLastModifiedEvent(this)); } @ModifiesData @@ -104,6 +111,7 @@ public void persist(Collection entities) { } catch (RuntimeException e) { throw new PersistenceException(e); } + eventPublisher.publishEvent(new RefreshLastModifiedEvent(this)); } @ModifiesData @@ -111,7 +119,9 @@ public void persist(Collection entities) { public T update(T entity) { Objects.requireNonNull(entity); try { - return em.merge(entity, getDescriptor()); + final T result = em.merge(entity, getDescriptor()); + eventPublisher.publishEvent(new RefreshLastModifiedEvent(this)); + return result; } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -124,7 +134,10 @@ public void remove(T entity) { Objects.requireNonNull(entity.getUri()); try { final Optional toRemove = find(entity.getUri()); - toRemove.ifPresent(em::remove); + toRemove.ifPresent(elem -> { + em.remove(elem); + eventPublisher.publishEvent(new RefreshLastModifiedEvent(this)); + }); } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -144,4 +157,9 @@ public boolean exists(URI id) { protected Descriptor getDescriptor() { return new EntityDescriptor(); } + + @Override + public void setApplicationEventPublisher(@NotNull ApplicationEventPublisher eventPublisher) { + this.eventPublisher = eventPublisher; + } } 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 90717ade6..b0c5ac077 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 @@ -80,6 +80,7 @@ public void persist(Resource resource, cz.cvut.kbss.termit.model.Vocabulary voca } catch (RuntimeException e) { throw new PersistenceException(e); } + refreshLastModified(); } private Descriptor createDescriptor(Resource resource, URI vocabularyUri) { @@ -98,26 +99,28 @@ private Descriptor createDescriptor(Resource resource, URI vocabularyUri) { @ModifiesData @Override public Resource update(Resource entity) { + final Resource updated; try { final URI vocabularyId = resolveVocabularyId(entity); if (vocabularyId != null) { setDocumentOnFileIfNecessary(entity, vocabularyId); // This evict is a bit overkill, but there are multiple relationships that would have to be evicted em.getEntityManagerFactory().getCache().evict(vocabularyId); - return em.merge(entity, createDescriptor(entity, vocabularyId)); + updated = em.merge(entity, createDescriptor(entity, vocabularyId)); } else { - return em.merge(entity); + updated = em.merge(entity); } } catch (RuntimeException e) { throw new PersistenceException(e); } + refreshLastModified(); + return updated; } private URI resolveVocabularyId(Resource resource) { if (resource instanceof Document) { return ((Document) resource).getVocabulary(); - } else if (resource instanceof File) { - final File f = (File) resource; + } else if (resource instanceof File f) { if (f.getDocument() != null) { return f.getDocument().getVocabulary(); } @@ -138,11 +141,11 @@ private void setDocumentOnFileIfNecessary(Resource file, URI vocabularyId) { public List findAll() { try { return em.createNativeQuery("SELECT ?x WHERE {" + - "?x a ?type ;" + - "?hasLabel ?label ." + - "FILTER NOT EXISTS { ?y ?hasFile ?x . } " + - "FILTER NOT EXISTS { ?x a ?vocabulary . } " + - "} ORDER BY LCASE(?label)", Resource.class) + "?x a ?type ;" + + "?hasLabel ?label ." + + "FILTER NOT EXISTS { ?y ?hasFile ?x . } " + + "FILTER NOT EXISTS { ?x a ?vocabulary . } " + + "} ORDER BY LCASE(?label)", Resource.class) .setParameter("type", typeUri) .setParameter("hasLabel", labelProperty()) .setParameter("hasFile", URI.create(Vocabulary.s_p_ma_soubor)) 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 93180ff65..62bc432e1 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 @@ -170,7 +170,9 @@ public Vocabulary update(Vocabulary entity) { try { // Evict possibly cached instance loaded from default context em.getEntityManagerFactory().getCache().evict(Vocabulary.class, entity.getUri(), null); - return em.merge(entity, descriptorFactory.vocabularyDescriptor(entity)); + final Vocabulary result = em.merge(entity, descriptorFactory.vocabularyDescriptor(entity)); + refreshLastModified(); + return result; } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -185,6 +187,7 @@ public void persist(Vocabulary entity) { if (entity.getDocument() != null && em.find(Document.class, entity.getDocument().getUri()) == null) { em.persist(entity.getDocument(), descriptorFactory.documentDescriptor(entity)); } + refreshLastModified(); } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -195,7 +198,10 @@ public void persist(Vocabulary entity) { public void remove(Vocabulary entity) { Objects.requireNonNull(entity); try { - find(entity.getUri()).ifPresent(em::remove); + find(entity.getUri()).ifPresent(elem -> { + em.remove(elem); + refreshLastModified(); + }); } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -238,7 +244,9 @@ public void forceRemove(Vocabulary entity) { */ public Glossary updateGlossary(Vocabulary entity) { Objects.requireNonNull(entity); - return em.merge(entity.getGlossary(), descriptorFactory.glossaryDescriptor(entity)); + final Glossary result = em.merge(entity.getGlossary(), descriptorFactory.glossaryDescriptor(entity)); + refreshLastModified(); + return result; } /** @@ -408,15 +416,16 @@ public Set getRelatedVocabularies(Vocabulary rootVocabulary, Collection toAdd = new HashSet<>(em.createNativeQuery("SELECT DISTINCT ?v WHERE {\n" + - " ?t a ?term ;\n" + - " ?inVocabulary ?vocabulary ;\n" + - " ?y ?z .\n" + - " ?z a ?term ;\n" + - " ?inVocabulary ?v .\n" + - " FILTER (?v != ?vocabulary)\n" + - " FILTER (?y IN (?cascadingRelationships))\n" + - "}", URI.class) + final Set toAdd = new HashSet<>(em.createNativeQuery(""" + SELECT DISTINCT ?v WHERE { + ?t a ?term ; + ?inVocabulary ?vocabulary ; + ?y ?z . + ?z a ?term ; + ?inVocabulary ?v . + FILTER (?v != ?vocabulary) + FILTER (?y IN (?cascadingRelationships)) + }""", URI.class) .setParameter("term", URI.create(SKOS.CONCEPT)) .setParameter("inVocabulary", URI.create( @@ -456,7 +465,7 @@ public PrefixDeclaration resolvePrefix(URI vocabularyUri) { .setParameter("hasNamespace", URI.create( cz.cvut.kbss.termit.util.Vocabulary.s_p_preferredNamespaceUri)) .getResultList(); - if (result.size() == 0) { + if (result.isEmpty()) { return PrefixDeclaration.EMPTY_PREFIX; } assert result.get(0) instanceof Object[]; diff --git a/src/main/java/cz/cvut/kbss/termit/rest/VocabularyController.java b/src/main/java/cz/cvut/kbss/termit/rest/VocabularyController.java index 4c42a4513..c4286bcbc 100644 --- a/src/main/java/cz/cvut/kbss/termit/rest/VocabularyController.java +++ b/src/main/java/cz/cvut/kbss/termit/rest/VocabularyController.java @@ -69,9 +69,9 @@ /** * Vocabulary management REST API. - * - * Note that most endpoints are now secured only by requiring the user to be authenticated, authorization is done - * on service level based on ACL. + *

+ * Note that most endpoints are now secured only by requiring the user to be authenticated, authorization is done on + * service level based on ACL. */ @Tag(name = "Vocabularies", description = "Vocabulary management API") @RestController diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTest.java index edf377c6e..b426920f0 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEventPublisher; import java.util.Collections; import java.util.List; @@ -49,11 +50,15 @@ class BaseDaoTest extends BaseDaoTestRunner { @Autowired private EntityManager em; + @Autowired + private ApplicationEventPublisher eventPublisher; + private BaseDao sut; @BeforeEach void setUp() { this.sut = new BaseDaoImpl(em); + sut.setApplicationEventPublisher(eventPublisher); } @Test From d7646ec88cff260181d6bd975554ff62cbc6f1e3 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Mon, 15 Jul 2024 08:50:24 +0200 Subject: [PATCH 03/11] [GH-268] Remove VocabularyContentModificationAspect, rewrite related logic to events. --- .../VocabularyContentModificationAspect.java | 41 ------------ .../kbss/termit/config/ServiceConfig.java | 7 --- .../event/VocabularyContentModified.java | 11 +++- .../kbss/termit/persistence/dao/TermDao.java | 10 ++- .../kbss/termit/service/jmx/AppAdminBean.java | 2 +- .../config/TestPersistenceAspectsConfig.java | 12 ---- .../config/TestPersistenceConfig.java | 10 +++ .../environment/config/TestServiceConfig.java | 6 -- .../termit/persistence/dao/TermDaoTest.java | 63 ++++++++++++++++++- .../ResultCachingValidatorTest.java | 4 +- 10 files changed, 93 insertions(+), 73 deletions(-) delete mode 100644 src/main/java/cz/cvut/kbss/termit/aspect/VocabularyContentModificationAspect.java diff --git a/src/main/java/cz/cvut/kbss/termit/aspect/VocabularyContentModificationAspect.java b/src/main/java/cz/cvut/kbss/termit/aspect/VocabularyContentModificationAspect.java deleted file mode 100644 index dae9c9304..000000000 --- a/src/main/java/cz/cvut/kbss/termit/aspect/VocabularyContentModificationAspect.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * TermIt - * Copyright (C) 2023 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 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 . - */ -package cz.cvut.kbss.termit.aspect; - -import cz.cvut.kbss.termit.event.VocabularyContentModified; -import org.aspectj.lang.annotation.After; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; - -@Aspect -public class VocabularyContentModificationAspect { - - @Autowired - private ApplicationEventPublisher eventPublisher; - - @Pointcut("@annotation(cz.cvut.kbss.termit.asset.provenance.ModifiesData) && target(cz.cvut.kbss.termit.persistence.dao.TermDao)") - public void vocabularyContentModificationOperation() { - } - - @After("vocabularyContentModificationOperation()") - public void vocabularyContentModified() { - eventPublisher.publishEvent(new VocabularyContentModified(this)); - } -} diff --git a/src/main/java/cz/cvut/kbss/termit/config/ServiceConfig.java b/src/main/java/cz/cvut/kbss/termit/config/ServiceConfig.java index 7f749d9ba..cea8465a8 100644 --- a/src/main/java/cz/cvut/kbss/termit/config/ServiceConfig.java +++ b/src/main/java/cz/cvut/kbss/termit/config/ServiceConfig.java @@ -19,7 +19,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import cz.cvut.kbss.termit.aspect.ChangeTrackingAspect; -import cz.cvut.kbss.termit.aspect.VocabularyContentModificationAspect; import cz.cvut.kbss.termit.exception.ResourceNotFoundException; import cz.cvut.kbss.termit.util.Utils; import org.apache.hc.client5.http.classic.HttpClient; @@ -114,10 +113,4 @@ ChangeTrackingAspect changeTrackingAspect() { // Need to create the aspect as a bean, so that it can be injected into return Aspects.aspectOf(ChangeTrackingAspect.class); } - - @Bean - VocabularyContentModificationAspect vocabularyContentModificationAspect() { - // Need to create the aspect as a bean, so that it can be injected into - return Aspects.aspectOf(VocabularyContentModificationAspect.class); - } } diff --git a/src/main/java/cz/cvut/kbss/termit/event/VocabularyContentModified.java b/src/main/java/cz/cvut/kbss/termit/event/VocabularyContentModified.java index 01595d0fa..8eed780fd 100644 --- a/src/main/java/cz/cvut/kbss/termit/event/VocabularyContentModified.java +++ b/src/main/java/cz/cvut/kbss/termit/event/VocabularyContentModified.java @@ -19,6 +19,8 @@ import org.springframework.context.ApplicationEvent; +import java.net.URI; + /** * Represents an event of modification of the content of a vocabulary. *

@@ -26,7 +28,14 @@ */ public class VocabularyContentModified extends ApplicationEvent { - public VocabularyContentModified(Object source) { + private final URI vocabularyIri; + + public VocabularyContentModified(Object source, URI vocabularyIri) { super(source); + this.vocabularyIri = vocabularyIri; + } + + public URI getVocabularyIri() { + return vocabularyIri; } } 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 3d12e1bed..f5700f99e 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 @@ -25,6 +25,7 @@ import cz.cvut.kbss.termit.dto.TermInfo; import cz.cvut.kbss.termit.dto.listing.TermDto; import cz.cvut.kbss.termit.event.EvictCacheEvent; +import cz.cvut.kbss.termit.event.VocabularyContentModified; import cz.cvut.kbss.termit.exception.PersistenceException; import cz.cvut.kbss.termit.model.AbstractTerm; import cz.cvut.kbss.termit.model.Term; @@ -170,6 +171,7 @@ public void persist(Term entity, Vocabulary vocabulary) { entity.setVocabulary(null); // This is inferred em.persist(entity, descriptorFactory.termDescriptor(vocabulary)); evictCachedSubTerms(Collections.emptySet(), entity.getParentTerms()); + eventPublisher.publishEvent(new VocabularyContentModified(this, vocabulary.getUri())); } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -186,7 +188,9 @@ public Term update(Term entity) { final Term original = em.find(Term.class, entity.getUri(), descriptorFactory.termDescriptor(entity)); entity.setDefinitionSource(original.getDefinitionSource()); evictCachedSubTerms(original.getParentTerms(), entity.getParentTerms()); - return em.merge(entity, descriptorFactory.termDescriptor(entity)); + final Term result = em.merge(entity, descriptorFactory.termDescriptor(entity)); + eventPublisher.publishEvent(new VocabularyContentModified(this, original.getVocabulary())); + return result; } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -603,7 +607,6 @@ public List findAll(String searchString, Vocabulary vocabulary) { public List findAll(String searchString) { Objects.requireNonNull(searchString); final TypedQuery query = em.createNativeQuery("SELECT DISTINCT ?term WHERE {" + - "" + "?term a ?type ; " + " ?hasLabel ?label ; " + "FILTER CONTAINS(LCASE(?label), LCASE(?searchString)) ." + @@ -727,10 +730,12 @@ public List findAllUnused(Vocabulary vocabulary) { .getResultList(); } + @ModifiesData @Override public void remove(Term entity) { super.remove(entity); evictCachedSubTerms(entity.getParentTerms(), Collections.emptySet()); + eventPublisher.publishEvent(new VocabularyContentModified(this, entity.getVocabulary())); } @Override @@ -751,7 +756,6 @@ public Optional findVersionValidAt(Term asset, Instant at) { @EventListener public void onEvictCache(EvictCacheEvent evt) { - subTermsCache.evictAll(); } } diff --git a/src/main/java/cz/cvut/kbss/termit/service/jmx/AppAdminBean.java b/src/main/java/cz/cvut/kbss/termit/service/jmx/AppAdminBean.java index 0ccf0c68c..a7abbc79e 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/jmx/AppAdminBean.java +++ b/src/main/java/cz/cvut/kbss/termit/service/jmx/AppAdminBean.java @@ -65,7 +65,7 @@ public void invalidateCaches() { eventPublisher.publishEvent(new EvictCacheEvent(this)); LOG.info("Refreshing last modified timestamps..."); eventPublisher.publishEvent(new RefreshLastModifiedEvent(this)); - eventPublisher.publishEvent(new VocabularyContentModified(this)); + eventPublisher.publishEvent(new VocabularyContentModified(this, null)); } @ManagedOperation(description = "Sends test email to the specified address.") diff --git a/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceAspectsConfig.java b/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceAspectsConfig.java index af49866f0..05f5f0ba4 100644 --- a/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceAspectsConfig.java +++ b/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceAspectsConfig.java @@ -18,11 +18,9 @@ package cz.cvut.kbss.termit.environment.config; import cz.cvut.kbss.termit.aspect.ChangeTrackingAspect; -import cz.cvut.kbss.termit.aspect.VocabularyContentModificationAspect; import cz.cvut.kbss.termit.service.changetracking.ChangeTracker; import org.aspectj.lang.Aspects; import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; @@ -41,14 +39,4 @@ public ChangeTrackingAspect changeTrackingAspect() { public ChangeTracker changeTracker() { return mock(ChangeTracker.class); } - - @Bean - VocabularyContentModificationAspect vocabularyContentModificationAspect() { - return Aspects.aspectOf(VocabularyContentModificationAspect.class); - } - - @Bean - public ApplicationEventPublisher eventPublisher() { - return mock(ApplicationEventPublisher.class); - } } 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 1fc4e8c2b..87b9a02cc 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 @@ -24,12 +24,16 @@ import cz.cvut.kbss.termit.workspace.EditableVocabulariesHolder; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.Primary; import org.springframework.transaction.annotation.EnableTransactionManagement; +import static org.mockito.Mockito.mock; + @TestConfiguration @EnableAspectJAutoProxy(proxyTargetClass = true) @Import({TestPersistenceFactory.class, PersistenceConfig.class}) @@ -41,4 +45,10 @@ public class TestPersistenceConfig { public EditableVocabularies editableVocabularies(Configuration config, ObjectProvider editableVocabulariesHolder) { return new EditableVocabularies(config, editableVocabulariesHolder); } + + @Bean + @Primary + public ApplicationEventPublisher eventPublisher() { + return mock(ApplicationEventPublisher.class); + } } diff --git a/src/test/java/cz/cvut/kbss/termit/environment/config/TestServiceConfig.java b/src/test/java/cz/cvut/kbss/termit/environment/config/TestServiceConfig.java index 41874802e..c56246128 100644 --- a/src/test/java/cz/cvut/kbss/termit/environment/config/TestServiceConfig.java +++ b/src/test/java/cz/cvut/kbss/termit/environment/config/TestServiceConfig.java @@ -18,7 +18,6 @@ package cz.cvut.kbss.termit.environment.config; import cz.cvut.kbss.termit.aspect.ChangeTrackingAspect; -import cz.cvut.kbss.termit.aspect.VocabularyContentModificationAspect; import cz.cvut.kbss.termit.dto.mapper.DtoMapper; import cz.cvut.kbss.termit.dto.mapper.DtoMapperImpl; import cz.cvut.kbss.termit.environment.Environment; @@ -101,11 +100,6 @@ ChangeTrackingAspect changeTrackingAspect() { return Aspects.aspectOf(ChangeTrackingAspect.class); } - @Bean - VocabularyContentModificationAspect vocabularyContentModificationAspect() { - return Aspects.aspectOf(VocabularyContentModificationAspect.class); - } - @Bean @Primary public ApplicationEventPublisher eventPublisher() { diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java index a9aa9b83f..9c94f3527 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java @@ -25,6 +25,7 @@ import cz.cvut.kbss.termit.dto.listing.TermDto; import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.event.VocabularyContentModified; import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.Term; import cz.cvut.kbss.termit.model.Term_; @@ -46,7 +47,10 @@ import org.eclipse.rdf4j.repository.RepositoryConnection; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.domain.PageRequest; import org.springframework.test.annotation.DirtiesContext; @@ -81,6 +85,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class TermDaoTest extends BaseTermDaoTestRunner { @@ -88,9 +94,13 @@ class TermDaoTest extends BaseTermDaoTestRunner { @Autowired private Configuration configuration; + @Autowired + private ApplicationEventPublisher eventPublisher; + @BeforeEach void setUp() { super.setUp(); + sut.setApplicationEventPublisher(eventPublisher); } private static List toDtos(List terms) { @@ -349,6 +359,17 @@ void persistEnsuresVocabularyAttributeIsEmptySoThatItCanBeInferred() { assertNull(result.getVocabulary()); } + @Test + void persistPublishesVocabularyContentModifiedEvent() { + final Term term = Generator.generateTermWithId(vocabulary.getUri()); + transactional(() -> sut.persist(term, vocabulary)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass( + VocabularyContentModified.class); + verify(eventPublisher).publishEvent(captor.capture()); + assertEquals(vocabulary.getUri(), captor.getValue().getVocabularyIri()); + } + @Test void updateUpdatesTermInVocabularyContext() { final Term term = Generator.generateTermWithId(vocabulary.getUri()); @@ -373,6 +394,26 @@ void updateUpdatesTermInVocabularyContext() { .setParameter("label", oldLabel, Environment.LANGUAGE).getSingleResult()); } + @Test + void updatePublishesVocabularyContentModifiedEvent() { + final Term term = Generator.generateTermWithId(vocabulary.getUri()); + transactional(() -> { + vocabulary.getGlossary().addRootTerm(term); + term.setGlossary(vocabulary.getGlossary().getUri()); + em.merge(vocabulary.getGlossary(), descriptorFactory.glossaryDescriptor(vocabulary)); + em.persist(term, descriptorFactory.termDescriptor(vocabulary)); + Generator.addTermInVocabularyRelationship(term, vocabulary.getUri(), em); + }); + + final String updatedLabel = "Updated label"; + term.setPrimaryLabel(updatedLabel); + transactional(() -> sut.update(term)); + final ArgumentCaptor captor = ArgumentCaptor.forClass( + VocabularyContentModified.class); + verify(eventPublisher).publishEvent(captor.capture()); + assertEquals(vocabulary.getUri(), captor.getValue().getVocabularyIri()); + } + @Test void findAllRootsReturnsOnlyTermsWithMatchingLabelLanguage() { final List terms = generateTerms(5); @@ -1153,7 +1194,7 @@ void removeEvictsParentsSubTermsCache() { em.merge(vocabulary.getGlossary(), descriptorFactory.glossaryDescriptor(vocabulary)); }); final List rootsBefore = sut.findAllRoots(vocabulary, Constants.DEFAULT_PAGE_SPEC, - Collections.emptyList()); + Collections.emptyList()); assertEquals(1, rootsBefore.size()); assertTrue(rootsBefore.get(0).getSubTerms().stream().anyMatch(ti -> ti.getUri().equals(term.getUri()))); @@ -1164,6 +1205,26 @@ void removeEvictsParentsSubTermsCache() { assertThat(roots.get(0).getSubTerms(), anyOf(nullValue(), emptyCollectionOf(TermInfo.class))); } + @Test + void removePublishesVocabularyContentModifiedEvent() { + final Term term = Generator.generateTermWithId(vocabulary.getUri()); + term.setGlossary(vocabulary.getGlossary().getUri()); + transactional(() -> { + vocabulary.getGlossary().addRootTerm(term); + em.persist(term, descriptorFactory.termDescriptor(vocabulary)); + em.merge(vocabulary.getGlossary(), descriptorFactory.glossaryDescriptor(vocabulary)); + }); + + transactional(() -> sut.remove(term)); + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream() + .filter(VocabularyContentModified.class::isInstance) + .map(VocabularyContentModified.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(vocabulary.getUri(), evt.get().getVocabularyIri()); + } + @Test void setStateUpdatesStateOfSpecifiedTerm() { final Term term = Generator.generateTermWithId(vocabulary.getUri()); diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/validation/ResultCachingValidatorTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/validation/ResultCachingValidatorTest.java index e2f1e967f..cc38b77fc 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/validation/ResultCachingValidatorTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/validation/ResultCachingValidatorTest.java @@ -32,6 +32,7 @@ import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @@ -75,8 +76,9 @@ void evictCacheClearsCachedValidationResults() { when(validator.validate(anyCollection())).thenReturn(results); final Set vocabularies = Collections.singleton(Generator.generateUri()); final List resultOne = sut.validate(vocabularies); - sut.evictCache(new VocabularyContentModified(this)); + sut.evictCache(new VocabularyContentModified(this, null)); final List resultTwo = sut.validate(vocabularies); verify(validator, times(2)).validate(vocabularies); + assertNotSame(resultOne, resultTwo); } } From 1a4c79aa0a08ee523f35afa18368e1a65d7fa8a7 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Mon, 15 Jul 2024 08:54:27 +0200 Subject: [PATCH 04/11] [Ref] Minor refactoring based on IDE suggestions. --- .../cz/cvut/kbss/termit/service/jmx/AppAdminBean.java | 5 +++-- .../cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java | 9 ++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/termit/service/jmx/AppAdminBean.java b/src/main/java/cz/cvut/kbss/termit/service/jmx/AppAdminBean.java index a7abbc79e..ae8019e24 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/jmx/AppAdminBean.java +++ b/src/main/java/cz/cvut/kbss/termit/service/jmx/AppAdminBean.java @@ -24,6 +24,7 @@ import cz.cvut.kbss.termit.service.mail.Message; import cz.cvut.kbss.termit.service.mail.Postman; import cz.cvut.kbss.termit.util.Configuration; +import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -76,7 +77,7 @@ public void sendTestEmail(String address) { } @Override - public ObjectName getObjectName() throws MalformedObjectNameException { + public @NotNull ObjectName getObjectName() throws MalformedObjectNameException { return new ObjectName("bean:name=" + beanName); } @@ -84,7 +85,7 @@ public ObjectName getObjectName() throws MalformedObjectNameException { * Gets health info of the application. *

* This method provides basic info on the status of the system. - * + *

* TODO Resolve status of services used by TermIt (repository, annotace, mail server - if configured) * * @return Health info object diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java index 9c94f3527..3829b6ba3 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java @@ -82,6 +82,7 @@ import static org.hamcrest.Matchers.nullValue; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -786,17 +787,15 @@ private void verifyTermSourceStatements(Term term) { final ValueFactory vf = conn.getValueFactory(); final IRI subject = vf.createIRI(term.getUri().toString()); final IRI hasSource = vf.createIRI(DC.Terms.SOURCE); - final List sourceStatements = conn.getStatements(subject, hasSource, null).stream().collect( - Collectors.toList()); + final List sourceStatements = conn.getStatements(subject, hasSource, null).stream().toList(); assertEquals(term.getSources().size(), sourceStatements.size()); sourceStatements.forEach(ss -> { assertTrue(term.getSources().contains(ss.getObject().stringValue())); - if (ss.getObject() instanceof Literal) { - final Literal litSource = (Literal) ss.getObject(); + if (ss.getObject() instanceof Literal litSource) { assertFalse(litSource.getLanguage().isPresent()); assertEquals(XSD.STRING, litSource.getDatatype()); } else { - assertTrue(ss.getObject() instanceof IRI); + assertInstanceOf(IRI.class, ss.getObject()); } }); } From ae9d6fca9c453bae056f93a3a5b6b32bb6e715b0 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Mon, 15 Jul 2024 12:42:16 +0200 Subject: [PATCH 05/11] [GH-268] Rewrite asset persist change tracking from aspect to application events. --- .../termit/aspect/ChangeTrackingAspect.java | 24 ------- .../kbss/termit/event/AssetPersistEvent.java | 21 ++++++ .../termit/persistence/dao/BaseAssetDao.java | 7 ++ .../kbss/termit/persistence/dao/TermDao.java | 2 + .../termit/persistence/dao/VocabularyDao.java | 2 + .../service/changetracking/ChangeTracker.java | 42 ++++++----- .../persistence/dao/BaseAssetDaoTest.java | 71 +++++++++++++++++++ .../termit/persistence/dao/TermDaoTest.java | 26 +++++-- .../persistence/dao/VocabularyDaoTest.java | 23 ++++++ .../changetracking/ChangeTrackerTest.java | 5 +- 10 files changed, 177 insertions(+), 46 deletions(-) create mode 100644 src/main/java/cz/cvut/kbss/termit/event/AssetPersistEvent.java create mode 100644 src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDaoTest.java diff --git a/src/main/java/cz/cvut/kbss/termit/aspect/ChangeTrackingAspect.java b/src/main/java/cz/cvut/kbss/termit/aspect/ChangeTrackingAspect.java index 241b25f46..0c1325984 100644 --- a/src/main/java/cz/cvut/kbss/termit/aspect/ChangeTrackingAspect.java +++ b/src/main/java/cz/cvut/kbss/termit/aspect/ChangeTrackingAspect.java @@ -19,10 +19,8 @@ import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.Term; -import cz.cvut.kbss.termit.model.Vocabulary; import cz.cvut.kbss.termit.persistence.dao.changetracking.ChangeTrackingHelperDao; import cz.cvut.kbss.termit.service.changetracking.ChangeTracker; -import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @@ -46,16 +44,6 @@ public class ChangeTrackingAspect { @Autowired private ChangeTrackingHelperDao helperDao; - @Pointcut(value = "execution(public void persist(..)) && (target(cz.cvut.kbss.termit.persistence.dao.BaseAssetDao)) " + - "&& @args(cz.cvut.kbss.termit.model.changetracking.Audited)") - public void persistOperation() { - } - - @Pointcut(value = "execution(public void persist(..)) && target(cz.cvut.kbss.termit.persistence.dao.TermDao) " + - "&& @args(cz.cvut.kbss.termit.model.changetracking.Audited, *)") - public void persistTermOperation() { - } - @Pointcut(value = "execution(public * update(..)) && target(cz.cvut.kbss.termit.persistence.dao.BaseAssetDao) " + "&& @args(cz.cvut.kbss.termit.model.changetracking.Audited)") public void updateOperation() { @@ -66,18 +54,6 @@ public void updateOperation() { public void termStateUpdateOperation() { } - @After(value = "persistOperation() && args(asset)") - public void recordAssetPersist(Asset asset) { - LOG.trace("Recording creation of asset {}.", asset); - changeTracker.recordAddEvent(asset); - } - - @After(value = "persistTermOperation() && args(asset, voc)", argNames = "asset,voc") - public void recordTermPersist(Term asset, Vocabulary voc) { - LOG.trace("Recording creation of term {}.", asset); - changeTracker.recordAddEvent(asset); - } - @Before(value = "updateOperation() && args(asset)") public void recordAssetUpdate(Asset asset) { LOG.trace("Recording update of asset {}.", asset); diff --git a/src/main/java/cz/cvut/kbss/termit/event/AssetPersistEvent.java b/src/main/java/cz/cvut/kbss/termit/event/AssetPersistEvent.java new file mode 100644 index 000000000..9451d6bb8 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/event/AssetPersistEvent.java @@ -0,0 +1,21 @@ +package cz.cvut.kbss.termit.event; + +import cz.cvut.kbss.termit.model.Asset; +import org.springframework.context.ApplicationEvent; + +/** + * Event published when an asset is persisted. + */ +public class AssetPersistEvent extends ApplicationEvent { + + private final Asset asset; + + public AssetPersistEvent(Object source, Asset asset) { + super(source); + this.asset = asset; + } + + public Asset getAsset() { + return asset; + } +} diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDao.java index 31651ca6a..af6148575 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDao.java @@ -19,6 +19,7 @@ import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.termit.dto.RecentlyCommentedAsset; +import cz.cvut.kbss.termit.event.AssetPersistEvent; import cz.cvut.kbss.termit.exception.PersistenceException; import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.User; @@ -51,6 +52,12 @@ public abstract class BaseAssetDao> extends BaseDao { this.descriptorFactory = descriptorFactory; } + @Override + public void persist(T entity) { + super.persist(entity); + eventPublisher.publishEvent(new AssetPersistEvent(this, entity)); + } + /** * Finds unique last commented assets. * 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 f5700f99e..ea4971464 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 @@ -24,6 +24,7 @@ import cz.cvut.kbss.termit.dto.Snapshot; import cz.cvut.kbss.termit.dto.TermInfo; import cz.cvut.kbss.termit.dto.listing.TermDto; +import cz.cvut.kbss.termit.event.AssetPersistEvent; import cz.cvut.kbss.termit.event.EvictCacheEvent; import cz.cvut.kbss.termit.event.VocabularyContentModified; import cz.cvut.kbss.termit.exception.PersistenceException; @@ -172,6 +173,7 @@ public void persist(Term entity, Vocabulary vocabulary) { em.persist(entity, descriptorFactory.termDescriptor(vocabulary)); evictCachedSubTerms(Collections.emptySet(), entity.getParentTerms()); eventPublisher.publishEvent(new VocabularyContentModified(this, vocabulary.getUri())); + eventPublisher.publishEvent(new AssetPersistEvent(this, entity)); } catch (RuntimeException e) { throw new PersistenceException(e); } 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 62bc432e1..ffff7befc 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 @@ -26,6 +26,7 @@ import cz.cvut.kbss.termit.dto.AggregatedChangeInfo; import cz.cvut.kbss.termit.dto.PrefixDeclaration; import cz.cvut.kbss.termit.dto.Snapshot; +import cz.cvut.kbss.termit.event.AssetPersistEvent; import cz.cvut.kbss.termit.event.RefreshLastModifiedEvent; import cz.cvut.kbss.termit.exception.PersistenceException; import cz.cvut.kbss.termit.model.Glossary; @@ -188,6 +189,7 @@ public void persist(Vocabulary entity) { em.persist(entity.getDocument(), descriptorFactory.documentDescriptor(entity)); } refreshLastModified(); + eventPublisher.publishEvent(new AssetPersistEvent(this, entity)); } catch (RuntimeException e) { throw new PersistenceException(e); } diff --git a/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeTracker.java b/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeTracker.java index dbd6b9cc1..716f2e407 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeTracker.java +++ b/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeTracker.java @@ -17,17 +17,21 @@ */ package cz.cvut.kbss.termit.service.changetracking; +import cz.cvut.kbss.termit.event.AssetPersistEvent; import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.changetracking.AbstractChangeRecord; 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.dao.changetracking.ChangeRecordDao; import cz.cvut.kbss.termit.service.security.SecurityUtils; import cz.cvut.kbss.termit.util.Utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -58,20 +62,6 @@ public ChangeTracker(ChangeCalculator changeCalculator, ChangeRecordDao changeRe this.securityUtils = securityUtils; } - /** - * Records an asset addition to the repository. - * - * @param added The added asset - */ - @Transactional - public void recordAddEvent(Asset added) { - Objects.requireNonNull(added); - final AbstractChangeRecord changeRecord = new PersistChangeRecord(added); - changeRecord.setAuthor(securityUtils.getCurrentUser().toUser()); - changeRecord.setTimestamp(Utils.timestamp()); - changeRecordDao.persist(changeRecord, added); - } - /** * Records an asset update. *

@@ -88,8 +78,8 @@ public void recordUpdateEvent(Asset update, Asset original) { final User user = securityUtils.getCurrentUser().toUser(); final Collection changes = changeCalculator.calculateChanges(update, original); if (!changes.isEmpty()) { - LOG.trace("Found changes to attributes: " + changes.stream().map(ch -> ch.getChangedAttribute().toString()) - .collect(Collectors.joining(", "))); + LOG.trace("Found changes to attributes: {}", changes.stream().map(ch -> ch.getChangedAttribute().toString()) + .collect(Collectors.joining(", "))); } changes.forEach(ch -> { ch.setAuthor(user); @@ -97,4 +87,24 @@ public void recordUpdateEvent(Asset update, Asset original) { changeRecordDao.persist(ch, update); }); } + + /** + * Records an asset addition to the repository. + * + * @param event Event representing the asset persist + */ + @Transactional + @EventListener + public void onAssetPersistEvent(@NonNull AssetPersistEvent event) { + final Asset added = event.getAsset(); + if (added instanceof File) { + LOG.trace("Skipping recording of creation of file {}.", added); + return; + } + LOG.trace("Recording creation of asset {}.", added); + final AbstractChangeRecord changeRecord = new PersistChangeRecord(added); + changeRecord.setAuthor(securityUtils.getCurrentUser().toUser()); + changeRecord.setTimestamp(Utils.timestamp()); + changeRecordDao.persist(changeRecord, added); + } } diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDaoTest.java new file mode 100644 index 000000000..7d11c4264 --- /dev/null +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDaoTest.java @@ -0,0 +1,71 @@ +package cz.cvut.kbss.termit.persistence.dao; + +import cz.cvut.kbss.jopa.model.EntityManager; +import cz.cvut.kbss.jopa.vocabulary.SKOS; +import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.model.Term; +import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; +import cz.cvut.kbss.termit.util.Configuration; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; + +import java.net.URI; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; + +class BaseAssetDaoTest extends BaseDaoTestRunner{ + + @Autowired + private EntityManager em; + + @Autowired + private Configuration config; + + @Autowired + private DescriptorFactory descriptorFactory; + + @Autowired + private ApplicationEventPublisher eventPublisher; + + private BaseDao sut; + + @BeforeEach + void setUp() { + this.sut = new BaseAssetDaoImpl(em, config.getPersistence(), descriptorFactory); + sut.setApplicationEventPublisher(eventPublisher); + } + + @Test + void persistPublishesAssetPersistEvent() { + final Term t = Generator.generateTermWithId(); + + transactional(() -> sut.persist(t)); + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream() + .filter(AssetPersistEvent.class::isInstance) + .map(AssetPersistEvent.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(t, evt.get().getAsset()); + } + + private static class BaseAssetDaoImpl extends BaseAssetDao { + + BaseAssetDaoImpl(EntityManager em, Configuration.Persistence config, DescriptorFactory descriptorFactory) { + super(Term.class, em, config, descriptorFactory); + } + + @Override + protected URI labelProperty() { + return URI.create(SKOS.PREF_LABEL); + } + } +} diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java index 3829b6ba3..551a505e0 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java @@ -25,6 +25,7 @@ import cz.cvut.kbss.termit.dto.listing.TermDto; import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.event.AssetPersistEvent; import cz.cvut.kbss.termit.event.VocabularyContentModified; import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.Term; @@ -365,10 +366,27 @@ void persistPublishesVocabularyContentModifiedEvent() { final Term term = Generator.generateTermWithId(vocabulary.getUri()); transactional(() -> sut.persist(term, vocabulary)); - final ArgumentCaptor captor = ArgumentCaptor.forClass( - VocabularyContentModified.class); - verify(eventPublisher).publishEvent(captor.capture()); - assertEquals(vocabulary.getUri(), captor.getValue().getVocabularyIri()); + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream() + .filter(VocabularyContentModified.class::isInstance) + .map(VocabularyContentModified.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(vocabulary.getUri(), evt.get().getVocabularyIri()); + } + + @Test + void persistPublishesAssetPersistEvent() { + final Term term = Generator.generateTermWithId(vocabulary.getUri()); + transactional(() -> sut.persist(term, vocabulary)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream() + .filter(AssetPersistEvent.class::isInstance) + .map(AssetPersistEvent.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(term, evt.get().getAsset()); } @Test 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 a2917724a..57e4bc52d 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 @@ -26,6 +26,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.AssetPersistEvent; import cz.cvut.kbss.termit.event.RefreshLastModifiedEvent; import cz.cvut.kbss.termit.model.*; import cz.cvut.kbss.termit.model.changetracking.AbstractChangeRecord; @@ -41,7 +42,10 @@ import org.eclipse.rdf4j.repository.RepositoryConnection; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.test.annotation.DirtiesContext; import java.net.URI; @@ -58,6 +62,7 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.verify; @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class VocabularyDaoTest extends BaseDaoTestRunner { @@ -68,6 +73,9 @@ class VocabularyDaoTest extends BaseDaoTestRunner { @Autowired private DescriptorFactory descriptorFactory; + @Autowired + private ApplicationEventPublisher eventPublisher; + @Autowired private VocabularyDao sut; @@ -78,6 +86,7 @@ void setUp() { this.author = Generator.generateUserWithId(); transactional(() -> em.persist(author)); Environment.setCurrentUser(author); + sut.setApplicationEventPublisher(eventPublisher); } @Test @@ -328,6 +337,20 @@ void persistRefreshesLastModifiedValue() { assertThat(after, greaterThan(before)); } + @Test + void persistPublishesAssetPersistEvent() { + final Vocabulary voc = Generator.generateVocabularyWithId(); + transactional(() -> sut.persist(voc)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream() + .filter(AssetPersistEvent.class::isInstance) + .map(AssetPersistEvent.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(voc, evt.get().getAsset()); + } + @Test void removeRefreshesLastModifiedValue() { final long before = sut.getLastModified(); 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 69ead3e5f..4bf97d9a2 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 @@ -23,6 +23,7 @@ import cz.cvut.kbss.jopa.vocabulary.SKOS; import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.event.AssetPersistEvent; import cz.cvut.kbss.termit.model.Term; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.Vocabulary; @@ -72,13 +73,13 @@ void setUp() { } @Test - void recordAddEventStoresCreationChangeRecordInRepository() { + void onAssetPersistEventStoresCreationChangeRecordInRepository() { enableRdfsInference(em); final Term newTerm = Generator.generateTermWithId(); newTerm.setGlossary(vocabulary.getGlossary().getUri()); transactional(() -> { em.persist(newTerm, descriptorFactory.termDescriptor(vocabulary)); - sut.recordAddEvent(newTerm); + sut.onAssetPersistEvent(new AssetPersistEvent(this, newTerm)); }); final List result = findRecords(newTerm); From 07c8ea6494da5638c90bad059d276f996cb7e187 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Mon, 15 Jul 2024 13:56:25 +0200 Subject: [PATCH 06/11] [GH-268] Rewrite asset update change tracking from aspect to application events. --- .../termit/aspect/ChangeTrackingAspect.java | 74 ------------------- .../kbss/termit/config/ServiceConfig.java | 8 -- .../kbss/termit/event/AssetUpdateEvent.java | 21 ++++++ .../termit/persistence/dao/BaseAssetDao.java | 7 ++ .../termit/persistence/dao/ResourceDao.java | 2 + .../kbss/termit/persistence/dao/TermDao.java | 4 + .../termit/persistence/dao/VocabularyDao.java | 24 +++--- .../changetracking/ChangeCalculator.java | 2 +- .../service/changetracking/ChangeTracker.java | 23 ++++-- .../config/TestPersistenceAspectsConfig.java | 42 ----------- .../config/TestPersistenceConfig.java | 8 +- .../environment/config/TestServiceConfig.java | 14 ---- .../persistence/dao/BaseAssetDaoTest.java | 18 +++++ .../persistence/dao/BaseDaoTestRunner.java | 4 +- .../persistence/dao/ResourceDaoTest.java | 26 +++++++ .../termit/persistence/dao/TermDaoTest.java | 58 +++++++++++++-- .../persistence/dao/VocabularyDaoTest.java | 19 +++++ .../termit/service/BaseServiceTestRunner.java | 2 +- .../changetracking/ChangeTrackerTest.java | 26 ++++--- 19 files changed, 201 insertions(+), 181 deletions(-) delete mode 100644 src/main/java/cz/cvut/kbss/termit/aspect/ChangeTrackingAspect.java create mode 100644 src/main/java/cz/cvut/kbss/termit/event/AssetUpdateEvent.java delete mode 100644 src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceAspectsConfig.java diff --git a/src/main/java/cz/cvut/kbss/termit/aspect/ChangeTrackingAspect.java b/src/main/java/cz/cvut/kbss/termit/aspect/ChangeTrackingAspect.java deleted file mode 100644 index 0c1325984..000000000 --- a/src/main/java/cz/cvut/kbss/termit/aspect/ChangeTrackingAspect.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * TermIt - * Copyright (C) 2023 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 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 . - */ -package cz.cvut.kbss.termit.aspect; - -import cz.cvut.kbss.termit.model.Asset; -import cz.cvut.kbss.termit.model.Term; -import cz.cvut.kbss.termit.persistence.dao.changetracking.ChangeTrackingHelperDao; -import cz.cvut.kbss.termit.service.changetracking.ChangeTracker; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.aspectj.lang.annotation.Pointcut; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -import java.net.URI; - -/** - * Records changes to assets based on modification operations. - */ -@Aspect -public class ChangeTrackingAspect { - - private static final Logger LOG = LoggerFactory.getLogger(ChangeTrackingAspect.class); - - @Autowired - private ChangeTracker changeTracker; - - @Autowired - private ChangeTrackingHelperDao helperDao; - - @Pointcut(value = "execution(public * update(..)) && target(cz.cvut.kbss.termit.persistence.dao.BaseAssetDao) " + - "&& @args(cz.cvut.kbss.termit.model.changetracking.Audited)") - public void updateOperation() { - } - - @Pointcut(value = "execution(public void setState(..)) && target(cz.cvut.kbss.termit.persistence.dao.TermDao)" + - "&& @args(cz.cvut.kbss.termit.model.changetracking.Audited, *)") - public void termStateUpdateOperation() { - } - - @Before(value = "updateOperation() && args(asset)") - public void recordAssetUpdate(Asset asset) { - LOG.trace("Recording update of asset {}.", asset); - changeTracker.recordUpdateEvent(asset, helperDao.findStored(asset)); - } - - @Before(value = "termStateUpdateOperation() && args(asset, state)", argNames = "asset, state") - public void recordTermStateUpdate(Term asset, URI state) { - LOG.trace("Recording update of asset {}.", asset); - final Term original = new Term(); - original.setUri(asset.getUri()); - original.setState(helperDao.findStored(asset).getState()); - final Term update = new Term(); - update.setUri(asset.getUri()); - update.setState(state); - changeTracker.recordUpdateEvent(update, original); - } -} diff --git a/src/main/java/cz/cvut/kbss/termit/config/ServiceConfig.java b/src/main/java/cz/cvut/kbss/termit/config/ServiceConfig.java index cea8465a8..227406729 100644 --- a/src/main/java/cz/cvut/kbss/termit/config/ServiceConfig.java +++ b/src/main/java/cz/cvut/kbss/termit/config/ServiceConfig.java @@ -18,13 +18,11 @@ package cz.cvut.kbss.termit.config; import com.fasterxml.jackson.databind.ObjectMapper; -import cz.cvut.kbss.termit.aspect.ChangeTrackingAspect; import cz.cvut.kbss.termit.exception.ResourceNotFoundException; import cz.cvut.kbss.termit.util.Utils; import org.apache.hc.client5.http.classic.HttpClient; import org.apache.hc.client5.http.impl.DefaultRedirectStrategy; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; -import org.aspectj.lang.Aspects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; @@ -107,10 +105,4 @@ public Resource termStatesLanguageFile(cz.cvut.kbss.termit.util.Configuration co } return new ClassPathResource("languages/states.ttl"); } - - @Bean - ChangeTrackingAspect changeTrackingAspect() { - // Need to create the aspect as a bean, so that it can be injected into - return Aspects.aspectOf(ChangeTrackingAspect.class); - } } diff --git a/src/main/java/cz/cvut/kbss/termit/event/AssetUpdateEvent.java b/src/main/java/cz/cvut/kbss/termit/event/AssetUpdateEvent.java new file mode 100644 index 000000000..cece65039 --- /dev/null +++ b/src/main/java/cz/cvut/kbss/termit/event/AssetUpdateEvent.java @@ -0,0 +1,21 @@ +package cz.cvut.kbss.termit.event; + +import cz.cvut.kbss.termit.model.Asset; +import org.springframework.context.ApplicationEvent; + +/** + * Event published when an asset is updated. + */ +public class AssetUpdateEvent extends ApplicationEvent { + + private final Asset asset; + + public AssetUpdateEvent(Object source, Asset asset) { + super(source); + this.asset = asset; + } + + public Asset getAsset() { + return asset; + } +} diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDao.java index af6148575..bb6e26400 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDao.java @@ -20,6 +20,7 @@ import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.termit.dto.RecentlyCommentedAsset; import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.exception.PersistenceException; import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.User; @@ -58,6 +59,12 @@ public void persist(T entity) { eventPublisher.publishEvent(new AssetPersistEvent(this, entity)); } + @Override + public T update(T entity) { + eventPublisher.publishEvent(new AssetUpdateEvent(this, entity)); + return super.update(entity); + } + /** * Finds unique last commented assets. * 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 b0c5ac077..95ee66483 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 @@ -22,6 +22,7 @@ import cz.cvut.kbss.jopa.vocabulary.DC; import cz.cvut.kbss.termit.asset.provenance.ModifiesData; import cz.cvut.kbss.termit.asset.provenance.SupportsLastModification; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.event.RefreshLastModifiedEvent; import cz.cvut.kbss.termit.exception.PersistenceException; import cz.cvut.kbss.termit.model.resource.Document; @@ -114,6 +115,7 @@ public Resource update(Resource entity) { throw new PersistenceException(e); } refreshLastModified(); + eventPublisher.publishEvent(new AssetUpdateEvent(this, updated)); return updated; } 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 ea4971464..07fae2fe1 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 @@ -25,6 +25,7 @@ import cz.cvut.kbss.termit.dto.TermInfo; import cz.cvut.kbss.termit.dto.listing.TermDto; import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.event.EvictCacheEvent; import cz.cvut.kbss.termit.event.VocabularyContentModified; import cz.cvut.kbss.termit.exception.PersistenceException; @@ -189,6 +190,7 @@ public Term update(Term entity) { evictPossiblyCachedReferences(entity); final Term original = em.find(Term.class, entity.getUri(), descriptorFactory.termDescriptor(entity)); entity.setDefinitionSource(original.getDefinitionSource()); + eventPublisher.publishEvent(new AssetUpdateEvent(this, entity)); evictCachedSubTerms(original.getParentTerms(), entity.getParentTerms()); final Term result = em.merge(entity, descriptorFactory.termDescriptor(entity)); eventPublisher.publishEvent(new VocabularyContentModified(this, original.getVocabulary())); @@ -229,6 +231,8 @@ private void evictPossiblyCachedReferences(Term term) { * @param state State to set */ public void setState(Term term, URI state) { + term.setState(state); + eventPublisher.publishEvent(new AssetUpdateEvent(this, term)); evictPossiblyCachedReferences(term); em.createNativeQuery("DELETE {" + "?t ?hasState ?oldState ." + 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 ffff7befc..535293e90 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,6 +27,7 @@ import cz.cvut.kbss.termit.dto.PrefixDeclaration; import cz.cvut.kbss.termit.dto.Snapshot; import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.event.RefreshLastModifiedEvent; import cz.cvut.kbss.termit.exception.PersistenceException; import cz.cvut.kbss.termit.model.Glossary; @@ -166,14 +167,15 @@ public List getImportingVocabularies(Vocabulary vocabulary) { @ModifiesData @Override - public Vocabulary update(Vocabulary entity) { + public void persist(Vocabulary entity) { Objects.requireNonNull(entity); try { - // Evict possibly cached instance loaded from default context - em.getEntityManagerFactory().getCache().evict(Vocabulary.class, entity.getUri(), null); - final Vocabulary result = em.merge(entity, descriptorFactory.vocabularyDescriptor(entity)); + em.persist(entity, descriptorFactory.vocabularyDescriptor(entity)); + if (entity.getDocument() != null && em.find(Document.class, entity.getDocument().getUri()) == null) { + em.persist(entity.getDocument(), descriptorFactory.documentDescriptor(entity)); + } refreshLastModified(); - return result; + eventPublisher.publishEvent(new AssetPersistEvent(this, entity)); } catch (RuntimeException e) { throw new PersistenceException(e); } @@ -181,15 +183,15 @@ public Vocabulary update(Vocabulary entity) { @ModifiesData @Override - public void persist(Vocabulary entity) { + public Vocabulary update(Vocabulary entity) { Objects.requireNonNull(entity); try { - em.persist(entity, descriptorFactory.vocabularyDescriptor(entity)); - if (entity.getDocument() != null && em.find(Document.class, entity.getDocument().getUri()) == null) { - em.persist(entity.getDocument(), descriptorFactory.documentDescriptor(entity)); - } + eventPublisher.publishEvent(new AssetUpdateEvent(this, entity)); + // Evict possibly cached instance loaded from default context + em.getEntityManagerFactory().getCache().evict(Vocabulary.class, entity.getUri(), null); + final Vocabulary result = em.merge(entity, descriptorFactory.vocabularyDescriptor(entity)); refreshLastModified(); - eventPublisher.publishEvent(new AssetPersistEvent(this, entity)); + return result; } catch (RuntimeException e) { throw new PersistenceException(e); } diff --git a/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeCalculator.java b/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeCalculator.java index cfa26c46a..76aaddbcf 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeCalculator.java +++ b/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeCalculator.java @@ -25,7 +25,7 @@ /** * Calculates changes made to an asset when compared to its original from the repository. */ -interface ChangeCalculator { +public interface ChangeCalculator { /** * Calculates the set of changes made to the specified asset. diff --git a/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeTracker.java b/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeTracker.java index 716f2e407..de0de54e0 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeTracker.java +++ b/src/main/java/cz/cvut/kbss/termit/service/changetracking/ChangeTracker.java @@ -18,6 +18,7 @@ package cz.cvut.kbss.termit.service.changetracking; import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.changetracking.AbstractChangeRecord; @@ -25,6 +26,7 @@ import cz.cvut.kbss.termit.model.changetracking.UpdateChangeRecord; import cz.cvut.kbss.termit.model.resource.File; import cz.cvut.kbss.termit.persistence.dao.changetracking.ChangeRecordDao; +import cz.cvut.kbss.termit.persistence.dao.changetracking.ChangeTrackingHelperDao; import cz.cvut.kbss.termit.service.security.SecurityUtils; import cz.cvut.kbss.termit.util.Utils; import org.slf4j.Logger; @@ -37,7 +39,6 @@ import java.time.Instant; import java.util.Collection; -import java.util.Objects; import java.util.stream.Collectors; /** @@ -52,13 +53,16 @@ public class ChangeTracker { private final ChangeRecordDao changeRecordDao; + private final ChangeTrackingHelperDao helperDao; + private final SecurityUtils securityUtils; @Autowired public ChangeTracker(ChangeCalculator changeCalculator, ChangeRecordDao changeRecordDao, - SecurityUtils securityUtils) { + ChangeTrackingHelperDao helperDao, SecurityUtils securityUtils) { this.changeCalculator = changeCalculator; this.changeRecordDao = changeRecordDao; + this.helperDao = helperDao; this.securityUtils = securityUtils; } @@ -71,16 +75,19 @@ public ChangeTracker(ChangeCalculator changeCalculator, ChangeRecordDao changeRe * @param original The original version of the asset */ @Transactional - public void recordUpdateEvent(Asset update, Asset original) { - Objects.requireNonNull(update); - Objects.requireNonNull(original); + @EventListener(AssetUpdateEvent.class) + public void onAssetUpdateEvent(AssetUpdateEvent event) { + final Asset update = event.getAsset(); + final Asset original = helperDao.findStored(update); final Instant now = Utils.timestamp(); final User user = securityUtils.getCurrentUser().toUser(); final Collection changes = changeCalculator.calculateChanges(update, original); - if (!changes.isEmpty()) { - LOG.trace("Found changes to attributes: {}", changes.stream().map(ch -> ch.getChangedAttribute().toString()) - .collect(Collectors.joining(", "))); + if (changes.isEmpty()) { + return; } + LOG.trace("Recording update of asset {}.", update); + LOG.trace("Found changes to attributes: {}", changes.stream().map(ch -> ch.getChangedAttribute().toString()) + .collect(Collectors.joining(", "))); changes.forEach(ch -> { ch.setAuthor(user); ch.setTimestamp(now); diff --git a/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceAspectsConfig.java b/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceAspectsConfig.java deleted file mode 100644 index 05f5f0ba4..000000000 --- a/src/test/java/cz/cvut/kbss/termit/environment/config/TestPersistenceAspectsConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * TermIt - * Copyright (C) 2023 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 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 . - */ -package cz.cvut.kbss.termit.environment.config; - -import cz.cvut.kbss.termit.aspect.ChangeTrackingAspect; -import cz.cvut.kbss.termit.service.changetracking.ChangeTracker; -import org.aspectj.lang.Aspects; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; - -import static org.mockito.Mockito.mock; - -@TestConfiguration -public class TestPersistenceAspectsConfig { - - @Bean - public ChangeTrackingAspect changeTrackingAspect() { - return Aspects.aspectOf(ChangeTrackingAspect.class); - } - - @Bean - @Primary - public ChangeTracker changeTracker() { - return mock(ChangeTracker.class); - } -} 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 87b9a02cc..0bc340493 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 @@ -32,7 +32,7 @@ import org.springframework.context.annotation.Primary; import org.springframework.transaction.annotation.EnableTransactionManagement; -import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; @TestConfiguration @EnableAspectJAutoProxy(proxyTargetClass = true) @@ -46,9 +46,9 @@ public EditableVocabularies editableVocabularies(Configuration config, ObjectPro return new EditableVocabularies(config, editableVocabulariesHolder); } - @Bean + @Bean("spiedPublisher") @Primary - public ApplicationEventPublisher eventPublisher() { - return mock(ApplicationEventPublisher.class); + public ApplicationEventPublisher eventPublisher(ApplicationEventPublisher eventPublisher) { + return spy(eventPublisher); } } diff --git a/src/test/java/cz/cvut/kbss/termit/environment/config/TestServiceConfig.java b/src/test/java/cz/cvut/kbss/termit/environment/config/TestServiceConfig.java index c56246128..973b1424f 100644 --- a/src/test/java/cz/cvut/kbss/termit/environment/config/TestServiceConfig.java +++ b/src/test/java/cz/cvut/kbss/termit/environment/config/TestServiceConfig.java @@ -17,7 +17,6 @@ */ package cz.cvut.kbss.termit.environment.config; -import cz.cvut.kbss.termit.aspect.ChangeTrackingAspect; import cz.cvut.kbss.termit.dto.mapper.DtoMapper; import cz.cvut.kbss.termit.dto.mapper.DtoMapperImpl; import cz.cvut.kbss.termit.environment.Environment; @@ -25,10 +24,8 @@ import cz.cvut.kbss.termit.service.document.html.DummySelectorGenerator; import cz.cvut.kbss.termit.service.document.html.HtmlSelectorGenerators; import cz.cvut.kbss.termit.util.Configuration; -import org.aspectj.lang.Aspects; import org.jsoup.nodes.Element; import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Primary; @@ -95,17 +92,6 @@ public ClassPathResource termStatesLanguageFile() { return new ClassPathResource("languages/states.ttl"); } - @Bean - ChangeTrackingAspect changeTrackingAspect() { - return Aspects.aspectOf(ChangeTrackingAspect.class); - } - - @Bean - @Primary - public ApplicationEventPublisher eventPublisher() { - return mock(ApplicationEventPublisher.class); - } - @Bean public JavaMailSender javaMailSender() { return mock(JavaMailSender.class); diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDaoTest.java index 7d11c4264..30f4284ad 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseAssetDaoTest.java @@ -4,6 +4,7 @@ import cz.cvut.kbss.jopa.vocabulary.SKOS; import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.model.Term; import cz.cvut.kbss.termit.persistence.context.DescriptorFactory; import cz.cvut.kbss.termit.util.Configuration; @@ -57,6 +58,23 @@ void persistPublishesAssetPersistEvent() { assertEquals(t, evt.get().getAsset()); } + @Test + void updatePublishesAssetUpdateEvent() { + final Term t = Generator.generateTermWithId(); + transactional(() -> em.persist(t)); + t.setPrimaryLabel("Updated primary label"); + + transactional(() -> sut.update(t)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream() + .filter(AssetUpdateEvent.class::isInstance) + .map(AssetUpdateEvent.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(t, evt.get().getAsset()); + } + private static class BaseAssetDaoImpl extends BaseAssetDao { BaseAssetDaoImpl(EntityManager em, Configuration.Persistence config, DescriptorFactory descriptorFactory) { diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTestRunner.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTestRunner.java index 3b5e05d0c..ea352ec61 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTestRunner.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/BaseDaoTestRunner.java @@ -18,7 +18,6 @@ package cz.cvut.kbss.termit.persistence.dao; import cz.cvut.kbss.termit.environment.TransactionalTestRunner; -import cz.cvut.kbss.termit.environment.config.TestPersistenceAspectsConfig; import cz.cvut.kbss.termit.environment.config.TestPersistenceConfig; import cz.cvut.kbss.termit.util.Configuration; import org.junit.jupiter.api.extension.ExtendWith; @@ -34,7 +33,8 @@ @ExtendWith(SpringExtension.class) @EnableConfigurationProperties(Configuration.class) @EnableSpringConfigured -@ContextConfiguration(classes = {TestPersistenceConfig.class, TestPersistenceAspectsConfig.class}, initializers = {ConfigDataApplicationContextInitializer.class}) +@ContextConfiguration(classes = {TestPersistenceConfig.class}, + initializers = {ConfigDataApplicationContextInitializer.class}) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) @ActiveProfiles("test") public abstract class BaseDaoTestRunner extends TransactionalTestRunner { 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 66bf8473a..bda9eaf71 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 @@ -20,6 +20,7 @@ import cz.cvut.kbss.jopa.model.EntityManager; import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.event.RefreshLastModifiedEvent; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.Vocabulary; @@ -33,7 +34,10 @@ import org.eclipse.rdf4j.repository.RepositoryConnection; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.test.annotation.DirtiesContext; import java.util.Comparator; @@ -54,6 +58,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) class ResourceDaoTest extends BaseDaoTestRunner { @@ -61,6 +67,9 @@ class ResourceDaoTest extends BaseDaoTestRunner { @Autowired private EntityManager em; + @Autowired + private ApplicationEventPublisher eventPublisher; + @Autowired private DescriptorFactory descriptorFactory; @@ -74,6 +83,7 @@ void setUp() { this.user = Generator.generateUserWithId(); transactional(() -> em.persist(user)); Environment.setCurrentUser(user); + sut.setApplicationEventPublisher(eventPublisher); } private Resource generateResource() { @@ -330,6 +340,22 @@ void updateRefreshesLastModifiedValue() { assertThat(after, greaterThan(before)); } + @Test + void updatePublishesAssetUpdateEvent() { + final Resource resource = generateResource(); + final String newLabel = "New label"; + resource.setLabel(newLabel); + + transactional(() -> sut.update(resource)); + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream() + .filter(AssetUpdateEvent.class::isInstance) + .map(AssetUpdateEvent.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(resource, evt.get().getAsset()); + } + @Test void removeFileUpdatesParentDocumentInVocabularyContext() { final Document document = Generator.generateDocumentWithId(); diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java index 551a505e0..9acc6a73f 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java @@ -26,6 +26,7 @@ import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.event.VocabularyContentModified; import cz.cvut.kbss.termit.model.Asset; import cz.cvut.kbss.termit.model.Term; @@ -369,8 +370,8 @@ void persistPublishesVocabularyContentModifiedEvent() { final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); final Optional evt = captor.getAllValues().stream() - .filter(VocabularyContentModified.class::isInstance) - .map(VocabularyContentModified.class::cast).findFirst(); + .filter(VocabularyContentModified.class::isInstance) + .map(VocabularyContentModified.class::cast).findFirst(); assertTrue(evt.isPresent()); assertEquals(vocabulary.getUri(), evt.get().getVocabularyIri()); } @@ -427,10 +428,34 @@ void updatePublishesVocabularyContentModifiedEvent() { final String updatedLabel = "Updated label"; term.setPrimaryLabel(updatedLabel); transactional(() -> sut.update(term)); - final ArgumentCaptor captor = ArgumentCaptor.forClass( - VocabularyContentModified.class); - verify(eventPublisher).publishEvent(captor.capture()); - assertEquals(vocabulary.getUri(), captor.getValue().getVocabularyIri()); + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream().filter(VocabularyContentModified.class::isInstance) + .map(VocabularyContentModified.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(vocabulary.getUri(), evt.get().getVocabularyIri()); + } + + @Test + void updatePublishesAssetUpdateEvent() { + final Term term = Generator.generateTermWithId(vocabulary.getUri()); + transactional(() -> { + vocabulary.getGlossary().addRootTerm(term); + term.setGlossary(vocabulary.getGlossary().getUri()); + em.merge(vocabulary.getGlossary(), descriptorFactory.glossaryDescriptor(vocabulary)); + em.persist(term, descriptorFactory.termDescriptor(vocabulary)); + Generator.addTermInVocabularyRelationship(term, vocabulary.getUri(), em); + }); + + final String updatedLabel = "Updated label"; + term.setPrimaryLabel(updatedLabel); + transactional(() -> sut.update(term)); + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream().filter(AssetUpdateEvent.class::isInstance) + .map(AssetUpdateEvent.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(term, evt.get().getAsset()); } @Test @@ -1262,4 +1287,25 @@ void setStateUpdatesStateOfSpecifiedTerm() { .setParameter("hasState", URI.create(cz.cvut.kbss.termit.util.Vocabulary.s_p_ma_stav_pojmu)) .setParameter("oldState", Generator.TERM_STATES[0]).getSingleResult()); } + + @Test + void setStatePublishesAssetUpdateEvent() { + final Term term = Generator.generateTermWithId(vocabulary.getUri()); + term.setState(Generator.TERM_STATES[0]); + transactional(() -> { + vocabulary.getGlossary().addRootTerm(term); + term.setGlossary(vocabulary.getGlossary().getUri()); + em.merge(vocabulary.getGlossary(), descriptorFactory.glossaryDescriptor(vocabulary)); + em.persist(term, descriptorFactory.termDescriptor(vocabulary)); + Generator.addTermInVocabularyRelationship(term, vocabulary.getUri(), em); + }); + + transactional(() -> sut.setState(term, Generator.TERM_STATES[1])); + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream().filter(AssetUpdateEvent.class::isInstance) + .map(AssetUpdateEvent.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(term, evt.get().getAsset()); + } } 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 57e4bc52d..423fcf2e4 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,6 +27,7 @@ import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.event.RefreshLastModifiedEvent; import cz.cvut.kbss.termit.model.*; import cz.cvut.kbss.termit.model.changetracking.AbstractChangeRecord; @@ -62,6 +63,7 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.verify; @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @@ -376,6 +378,23 @@ void updateRefreshesLastModifiedValue() { assertThat(after, greaterThan(before)); } + @Test + void updatePublishesAssetUpdateEvent() { + final Vocabulary voc = Generator.generateVocabularyWithId(); + transactional(() -> em.persist(voc, descriptorFactory.vocabularyDescriptor(voc))); + final String newLabel = "New vocabulary label"; + voc.setLabel(MultilingualString.create(newLabel, Environment.LANGUAGE)); + + transactional(() -> sut.update(voc)); + final ArgumentCaptor captor = ArgumentCaptor.forClass(ApplicationEvent.class); + verify(eventPublisher, atLeastOnce()).publishEvent(captor.capture()); + final Optional evt = captor.getAllValues().stream() + .filter(AssetUpdateEvent.class::isInstance) + .map(AssetUpdateEvent.class::cast).findFirst(); + assertTrue(evt.isPresent()); + assertEquals(voc, evt.get().getAsset()); + } + @Test void getChangesOfContentLoadsAggregatedChangesOfTermsInVocabulary() { enableRdfsInference(em); 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 f46527af9..8ee8d349e 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/BaseServiceTestRunner.java +++ b/src/test/java/cz/cvut/kbss/termit/service/BaseServiceTestRunner.java @@ -46,7 +46,7 @@ TestServiceConfig.class}, initializers = {ConfigDataApplicationContextInitializer.class}) @ActiveProfiles("test") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) -public class BaseServiceTestRunner extends TransactionalTestRunner { +public abstract class BaseServiceTestRunner extends TransactionalTestRunner { private static final String EXISTENCE_CHECK_QUERY = "ASK { ?x a ?type . }"; 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 4bf97d9a2..c5f924074 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 @@ -24,6 +24,7 @@ import cz.cvut.kbss.termit.environment.Environment; import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.event.AssetPersistEvent; +import cz.cvut.kbss.termit.event.AssetUpdateEvent; import cz.cvut.kbss.termit.model.Term; import cz.cvut.kbss.termit.model.User; import cz.cvut.kbss.termit.model.Vocabulary; @@ -42,9 +43,13 @@ import java.util.List; import static cz.cvut.kbss.termit.service.changetracking.MetamodelBasedChangeCalculatorTest.cloneOf; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.CoreMatchers.anyOf; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; class ChangeTrackerTest extends BaseServiceTestRunner { @@ -92,7 +97,8 @@ void onAssetPersistEventStoresCreationChangeRecordInRepository() { } private List findRecords(HasIdentifier entity) { - return em.createNativeQuery("SELECT ?x WHERE { ?x a ?changeRecord ; ?concerns ?entity . }", AbstractChangeRecord.class) + return em.createNativeQuery("SELECT ?x WHERE { ?x a ?changeRecord ; ?concerns ?entity . }", + AbstractChangeRecord.class) .setParameter("changeRecord", URI.create(cz.cvut.kbss.termit.util.Vocabulary.s_c_zmena)) .setParameter("concerns", URI.create(cz.cvut.kbss.termit.util.Vocabulary.s_p_ma_zmenenou_entitu)) .setParameter("entity", entity.getUri()) @@ -100,20 +106,20 @@ private List findRecords(HasIdentifier entity) { } @Test - void recordUpdateEventDoesNothingWhenAssetDidNotChange() { + void onAssetUpdateEventEventDoesNothingWhenAssetDidNotChange() { enableRdfsInference(em); final Term original = Generator.generateTermWithId(); original.setVocabulary(vocabulary.getUri()); transactional(() -> em.persist(original, descriptorFactory.termDescriptor(original))); final Term update = cloneOf(original); - transactional(() -> sut.recordUpdateEvent(update, original)); + transactional(() -> sut.onAssetUpdateEvent(new AssetUpdateEvent(this, update))); assertTrue(findRecords(original).isEmpty()); } @Test - void recordUpdateRecordsSingleChangeToLiteralAttribute() { + void onAssetUpdateEventRecordsSingleChangeToLiteralAttribute() { enableRdfsInference(em); final Term original = Generator.generateTermWithId(); original.setGlossary(vocabulary.getGlossary().getUri()); @@ -121,7 +127,7 @@ void recordUpdateRecordsSingleChangeToLiteralAttribute() { final Term update = cloneOf(original); update.setDefinition(MultilingualString.create("Updated definition of this term.", Environment.LANGUAGE)); - transactional(() -> sut.recordUpdateEvent(update, original)); + transactional(() -> sut.onAssetUpdateEvent(new AssetUpdateEvent(this, update))); final List result = findRecords(original); assertEquals(1, result.size()); @@ -132,7 +138,7 @@ void recordUpdateRecordsSingleChangeToLiteralAttribute() { } @Test - void recordUpdateRecordsMultipleChangesToAttributes() { + void onAssetUpdateEventRecordsMultipleChangesToAttributes() { enableRdfsInference(em); final Term original = Generator.generateTermWithId(); original.setGlossary(vocabulary.getGlossary().getUri()); @@ -141,7 +147,7 @@ void recordUpdateRecordsMultipleChangesToAttributes() { final Term update = cloneOf(original); update.setDefinition(MultilingualString.create("Updated definition of this term.", Environment.LANGUAGE)); update.setSources(Collections.singleton(Generator.generateUri().toString())); - transactional(() -> sut.recordUpdateEvent(update, original)); + transactional(() -> sut.onAssetUpdateEvent(new AssetUpdateEvent(this, update))); final List result = findRecords(original); assertEquals(2, result.size()); @@ -149,7 +155,7 @@ void recordUpdateRecordsMultipleChangesToAttributes() { assertEquals(original.getUri(), record.getChangedEntity()); assertThat(record, instanceOf(UpdateChangeRecord.class)); assertThat(((UpdateChangeRecord) record).getChangedAttribute().toString(), anyOf(equalTo(SKOS.DEFINITION), - equalTo(DC.Terms.SOURCE))); + equalTo(DC.Terms.SOURCE))); }); } } From aca5cffe7105570ec07d47d40f1b0bf18de175f6 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Mon, 15 Jul 2024 14:31:20 +0200 Subject: [PATCH 07/11] [Upd] Update to Spring Boot 3.3.1 and JOPA 2.0.2. --- pom.xml | 8 +++----- .../kbss/termit/service/document/TextAnalysisService.java | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index 94154f29c..414c9b29a 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.5 + 3.3.1 termit @@ -31,7 +31,7 @@ 2.7.0 1.5.5.Final 2.2.0 - 2.0.0 + 2.0.2 0.14.3 @@ -112,7 +112,7 @@ org.eclipse.rdf4j rdf4j-rio-rdfxml - 4.3.11 + 5.0.0 @@ -437,8 +437,6 @@ 1.13.1 ${java.version} - ${java.version} - ${java.version} org.springframework diff --git a/src/main/java/cz/cvut/kbss/termit/service/document/TextAnalysisService.java b/src/main/java/cz/cvut/kbss/termit/service/document/TextAnalysisService.java index c2c7ae3c2..f68db9bb7 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/document/TextAnalysisService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/document/TextAnalysisService.java @@ -124,7 +124,7 @@ private Optional invokeTextAnalysisService(TextAnalysisInput input) { } final HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_XML_VALUE); - LOG.debug("Invoking text analysis service on input: {}", input); + LOG.debug("Invoking text analysis service at '{}' on input: {}", config.getTextAnalysis().getUrl(), input); final ResponseEntity resp = restClient .exchange(config.getTextAnalysis().getUrl(), HttpMethod.POST, new HttpEntity<>(input, headers), Resource.class); From c60aedb9386e0cefb1b84a53ea3cfd52921d9f02 Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 16 Jul 2024 15:10:42 +0200 Subject: [PATCH 08/11] Remove remaining references to class pdp:term. It is no longer used, we use skos:Concept. --- .../kbss/termit/persistence/dao/TermOccurrenceDao.java | 3 ++- .../validation/WithoutQueryParametersValidatorTest.java | 6 +++--- .../cz/cvut/kbss/termit/persistence/dao/DataDaoTest.java | 8 ++++---- .../cz/cvut/kbss/termit/rest/SearchControllerTest.java | 5 ++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermOccurrenceDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermOccurrenceDao.java index e3529e477..373991a1e 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermOccurrenceDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermOccurrenceDao.java @@ -23,6 +23,7 @@ import cz.cvut.kbss.jopa.model.query.Query; import cz.cvut.kbss.jopa.vocabulary.DC; import cz.cvut.kbss.jopa.vocabulary.RDFS; +import cz.cvut.kbss.jopa.vocabulary.SKOS; import cz.cvut.kbss.termit.dto.assignment.TermOccurrences; import cz.cvut.kbss.termit.exception.PersistenceException; import cz.cvut.kbss.termit.model.Asset; @@ -184,7 +185,7 @@ public List getOccurrenceInfo(Term term) { .setParameter("isDocumentOf", URI.create(Vocabulary.s_p_ma_soubor)) .setParameter("fileType", URI.create(Vocabulary.s_c_soubor)) .setParameter("lang", config.getLanguage()) - .setParameter("termType", URI.create(Vocabulary.s_c_term)) + .setParameter("termType", URI.create(SKOS.CONCEPT)) .setParameter("termDefOcc", URI.create(Vocabulary.s_c_definicni_vyskyt_termu)) .setParameter("fileOcc", URI.create(Vocabulary.s_c_souborovy_vyskyt_termu)) .setParameter("t", term.getUri()).getResultList(); diff --git a/src/test/java/cz/cvut/kbss/termit/model/util/validation/WithoutQueryParametersValidatorTest.java b/src/test/java/cz/cvut/kbss/termit/model/util/validation/WithoutQueryParametersValidatorTest.java index 5f5e1f676..acc33c0bc 100644 --- a/src/test/java/cz/cvut/kbss/termit/model/util/validation/WithoutQueryParametersValidatorTest.java +++ b/src/test/java/cz/cvut/kbss/termit/model/util/validation/WithoutQueryParametersValidatorTest.java @@ -17,14 +17,14 @@ */ package cz.cvut.kbss.termit.model.util.validation; +import cz.cvut.kbss.jopa.vocabulary.SKOS; import cz.cvut.kbss.termit.environment.Generator; -import cz.cvut.kbss.termit.util.Vocabulary; +import jakarta.validation.ConstraintValidatorContext; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import jakarta.validation.ConstraintValidatorContext; import java.net.URI; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -40,7 +40,7 @@ class WithoutQueryParametersValidatorTest { @Test void isValidReturnsTrueForNormalUris() { - final URI uri = URI.create(Vocabulary.s_c_term + Generator.randomInt(0, 1000000)); + final URI uri = URI.create(SKOS.CONCEPT + Generator.randomInt(0, 1000000)); assertTrue(sut.isValid(uri, ctx)); } diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/DataDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/DataDaoTest.java index 3fe2db5c1..55e3325bb 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/DataDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/DataDaoTest.java @@ -139,7 +139,7 @@ void getLabelReturnsLabelWithoutLanguageTagWhenMatchingLanguageTagDoesNotExist() final Repository repo = em.unwrap(Repository.class); final ValueFactory vf = repo.getValueFactory(); try (final RepositoryConnection connection = repo.getConnection()) { - connection.add(vf.createIRI(term.getUri().toString()), RDF.TYPE, vf.createIRI(Vocabulary.s_c_term)); + connection.add(vf.createIRI(term.getUri().toString()), RDF.TYPE, SKOS.CONCEPT); connection.add(vf.createIRI(term.getUri().toString()), SKOS.PREF_LABEL, vf.createLiteral(term.getPrimaryLabel())); connection.commit(); @@ -170,7 +170,7 @@ void getLabelReturnsEmptyOptionalForIdentifierWithMultipleLabels() { final Repository repo = em.unwrap(Repository.class); final ValueFactory vf = repo.getValueFactory(); try (final RepositoryConnection connection = repo.getConnection()) { - connection.add(vf.createIRI(term.getUri().toString()), RDF.TYPE, vf.createIRI(Vocabulary.s_c_term)); + connection.add(vf.createIRI(term.getUri().toString()), RDF.TYPE,SKOS.CONCEPT); connection.add(vf.createIRI(term.getUri().toString()), SKOS.PREF_LABEL, vf.createLiteral(term.getPrimaryLabel())); connection.add(vf.createIRI(term.getUri().toString()), SKOS.PREF_LABEL, @@ -234,7 +234,7 @@ void exportDataToTurtleExportsContextWhenProvided() { transactional(() -> { final Repository repo = em.unwrap(Repository.class); try (final RepositoryConnection connection = repo.getConnection()) { - connection.add(vf.createIRI(Vocabulary.s_c_term), RDFS.LABEL, vf.createLiteral("Term"), + connection.add(SKOS.CONCEPT, RDFS.LABEL, vf.createLiteral("Term"), vf.createIRI(context.toString())); connection.commit(); } @@ -242,7 +242,7 @@ void exportDataToTurtleExportsContextWhenProvided() { transactional(() -> { final TypeAwareResource result = sut.exportDataAsTurtle(context); Model model = parseExportToModel(result); - assertTrue(model.contains(vf.createIRI(Vocabulary.s_c_term), RDFS.LABEL, vf.createLiteral("Term"))); + assertTrue(model.contains(SKOS.CONCEPT, RDFS.LABEL, vf.createLiteral("Term"))); assertFalse(model.contains(vf.createIRI(Vocabulary.s_p_ma_krestni_jmeno), null, null)); }); } diff --git a/src/test/java/cz/cvut/kbss/termit/rest/SearchControllerTest.java b/src/test/java/cz/cvut/kbss/termit/rest/SearchControllerTest.java index da053fa69..d8abed694 100644 --- a/src/test/java/cz/cvut/kbss/termit/rest/SearchControllerTest.java +++ b/src/test/java/cz/cvut/kbss/termit/rest/SearchControllerTest.java @@ -29,7 +29,6 @@ import cz.cvut.kbss.termit.environment.Generator; import cz.cvut.kbss.termit.service.business.SearchService; import cz.cvut.kbss.termit.util.Constants; -import cz.cvut.kbss.termit.util.Vocabulary; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -76,7 +75,7 @@ void setUp() { void fullTextSearchExecutesSearchOnService() throws Exception { final List expected = Collections .singletonList( - new FullTextSearchResult(Generator.generateUri(), "test", null, null, Vocabulary.s_c_term, + new FullTextSearchResult(Generator.generateUri(), "test", null, null, SKOS.CONCEPT, "test", "test", 1.0)); when(searchServiceMock.fullTextSearch(any())).thenReturn(expected); final String searchString = "test"; @@ -97,7 +96,7 @@ void fullTextSearchOfTermsWithoutVocabularySpecificationExecutesSearchOnService( final URI vocabularyIri = URI.create("https://test.org/vocabulary"); final List expected = Collections .singletonList(new FullTextSearchResult(Generator.generateUri(), "test", vocabularyIri, null, - Vocabulary.s_c_term, "test", "test", 1.0)); + SKOS.CONCEPT, "test", "test", 1.0)); when(searchServiceMock.fullTextSearchOfTerms(any(), any())).thenReturn(expected); final String searchString = "test"; From e7c255f0c9fb106504c703411cc708c7447e374b Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 16 Jul 2024 15:18:08 +0200 Subject: [PATCH 09/11] =?UTF-8?q?[Fix]=20Escape=20the=20section=20sign=20(?= =?UTF-8?q?=C2=A7)=20when=20generating=20identifiers.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported in datagov-cz/sgov-assembly-line#198. The section sign is quite common in Czech legislation, so we need to handle it. --- .../cz/cvut/kbss/termit/service/IdentifierResolver.java | 2 +- .../cvut/kbss/termit/service/IdentifierResolverTest.java | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/cz/cvut/kbss/termit/service/IdentifierResolver.java b/src/main/java/cz/cvut/kbss/termit/service/IdentifierResolver.java index ff402eb06..1adb75184 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/IdentifierResolver.java +++ b/src/main/java/cz/cvut/kbss/termit/service/IdentifierResolver.java @@ -98,7 +98,7 @@ public static String normalize(String value) { return value.toLowerCase() .trim() .replaceAll("[\\s/\\\\]", Character.toString(REPLACEMENT_CHARACTER)) - .replaceAll("[(?&$#),]", ""); + .replaceAll("[(?&$#§),]", ""); } /** diff --git a/src/test/java/cz/cvut/kbss/termit/service/IdentifierResolverTest.java b/src/test/java/cz/cvut/kbss/termit/service/IdentifierResolverTest.java index 650bf3a77..d918e4574 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/IdentifierResolverTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/IdentifierResolverTest.java @@ -307,4 +307,12 @@ void generateIdentifierHandlesStringsWithReservedUriCharacters() { final String invalidString = "Bug #$# test"; assertDoesNotThrow(() -> sut.generateIdentifier(namespace, invalidString)); } + + @Test + void generateIdentifierRemovesSectionSign() { + final String namespace = Vocabulary.s_c_slovnik; + final String label = "je povinným subjektem podle §2 zákona 106/1999 Sb."; + final URI result = sut.generateIdentifier(namespace, label); + assertEquals(URI.create(namespace + "/je-povinným-subjektem-podle-2-zákona-106-1999-sb."), result); + } } From 0e4387122479946fa0e7e7c58ae421cc0389a15f Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 16 Jul 2024 16:08:19 +0200 Subject: [PATCH 10/11] [Enhancement #270] Pass repository username and password to annotace. --- .../kbss/termit/dto/TextAnalysisInput.java | 26 ++++++++++++ .../service/document/TextAnalysisService.java | 4 ++ .../document/TextAnalysisServiceTest.java | 41 +++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/src/main/java/cz/cvut/kbss/termit/dto/TextAnalysisInput.java b/src/main/java/cz/cvut/kbss/termit/dto/TextAnalysisInput.java index 72537cad0..e0e8cf7c1 100644 --- a/src/main/java/cz/cvut/kbss/termit/dto/TextAnalysisInput.java +++ b/src/main/java/cz/cvut/kbss/termit/dto/TextAnalysisInput.java @@ -44,6 +44,16 @@ public class TextAnalysisInput { */ private URI vocabularyRepository; + /** + * Username to access the repository + */ + private String vocabularyRepositoryUserName; + + /** + * Password to access the repository + */ + private String vocabularyRepositoryPassword; + /** * URIs of contexts containing vocabularies whose terms are used in the text analysis. Optional. *

@@ -84,6 +94,22 @@ public void setVocabularyRepository(URI vocabularyRepository) { this.vocabularyRepository = vocabularyRepository; } + public String getVocabularyRepositoryUserName() { + return vocabularyRepositoryUserName; + } + + public void setVocabularyRepositoryUserName(String vocabularyRepositoryUserName) { + this.vocabularyRepositoryUserName = vocabularyRepositoryUserName; + } + + public String getVocabularyRepositoryPassword() { + return vocabularyRepositoryPassword; + } + + public void setVocabularyRepositoryPassword(String vocabularyRepositoryPassword) { + this.vocabularyRepositoryPassword = vocabularyRepositoryPassword; + } + public Set getVocabularyContexts() { return vocabularyContexts; } diff --git a/src/main/java/cz/cvut/kbss/termit/service/document/TextAnalysisService.java b/src/main/java/cz/cvut/kbss/termit/service/document/TextAnalysisService.java index f68db9bb7..c5f81ba36 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/document/TextAnalysisService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/document/TextAnalysisService.java @@ -93,6 +93,8 @@ private TextAnalysisInput createAnalysisInput(File file) { ); input.setVocabularyRepository(repositoryUrl); input.setLanguage(config.getPersistence().getLanguage()); + input.setVocabularyRepositoryUserName(config.getRepository().getUsername()); + input.setVocabularyRepositoryPassword(config.getRepository().getPassword()); return input; } @@ -169,6 +171,8 @@ public void analyzeTermDefinition(AbstractTerm term, URI vocabularyContext) { final TextAnalysisInput input = new TextAnalysisInput(term.getDefinition().get(language), language, URI.create(config.getRepository().getUrl())); input.addVocabularyContext(vocabularyContext); + input.setVocabularyRepositoryUserName(config.getRepository().getUsername()); + input.setVocabularyRepositoryPassword(config.getRepository().getPassword()); invokeTextAnalysisOnTerm(term, input); } diff --git a/src/test/java/cz/cvut/kbss/termit/service/document/TextAnalysisServiceTest.java b/src/test/java/cz/cvut/kbss/termit/service/document/TextAnalysisServiceTest.java index 3327c4dab..4f56a27ba 100644 --- a/src/test/java/cz/cvut/kbss/termit/service/document/TextAnalysisServiceTest.java +++ b/src/test/java/cz/cvut/kbss/termit/service/document/TextAnalysisServiceTest.java @@ -167,6 +167,8 @@ private TextAnalysisInput textAnalysisInput() { ); input.setVocabularyRepository(repositoryUrl); input.setLanguage(config.getPersistence().getLanguage()); + input.setVocabularyRepositoryUserName(config.getRepository().getUsername()); + input.setVocabularyRepositoryPassword(config.getRepository().getPassword()); return input; } @@ -183,6 +185,23 @@ void analyzeFilePassesContentTypeAndAcceptHeadersToService() throws Exception { mockServer.verify(); } + @Test + void analyzeFilePassesRepositoryUsernameAndPasswordToServiceWhenProvided() throws Exception { + final String username = "user"; + config.getRepository().setUsername(username); + final String password = "password"; + config.getRepository().setPassword(password); + final TextAnalysisInput input = textAnalysisInput(); + input.setVocabularyRepositoryUserName(username); + input.setVocabularyRepositoryPassword(password); + mockServer.expect(requestTo(config.getTextAnalysis().getUrl())) + .andExpect(method(HttpMethod.POST)) + .andExpect(content().string(objectMapper.writeValueAsString(input))) + .andRespond(withSuccess(CONTENT, MediaType.APPLICATION_XML)); + sut.analyzeFile(file, Collections.singleton(vocabulary.getUri())); + mockServer.verify(); + } + @Test void analyzeFileThrowsWebServiceIntegrationExceptionOnError() throws Exception { final TextAnalysisInput input = textAnalysisInput(); @@ -353,4 +372,26 @@ void analyzeTermDefinitionDoesNothingWhenTextAnalysisServiceUrlIsNotConfigured() verify(annotationGeneratorMock, never()).generateAnnotations(any(), any(Term.class)); verify(textAnalysisRecordDao, never()).persist(any()); } + + @Test + void analyzeTermDefinitionInvokesTextAnalysisServiceWithVocabularyRepositoryUsernameAndPassword() + throws Exception { + final Term term = Generator.generateTermWithId(); + term.setVocabulary(vocabulary.getUri()); + final TextAnalysisInput input = textAnalysisInput(); + input.setContent(term.getDefinition().get(Environment.LANGUAGE)); + final String username = "user"; + config.getRepository().setUsername(username); + final String password = "password"; + config.getRepository().setPassword(password); + input.setVocabularyRepositoryUserName(username); + input.setVocabularyRepositoryPassword(password); + mockServer.expect(requestTo(config.getTextAnalysis().getUrl())) + .andExpect(method(HttpMethod.POST)) + .andExpect(content().string(objectMapper.writeValueAsString(input))) + .andRespond(withSuccess(CONTENT, MediaType.APPLICATION_XML)); + + sut.analyzeTermDefinition(term, vocabulary.getUri()); + mockServer.verify(); + } } From 500e84c82dace3d1055390e1c4b6b2b015c0a60c Mon Sep 17 00:00:00 2001 From: Martin Ledvinka Date: Tue, 16 Jul 2024 17:10:20 +0200 Subject: [PATCH 11/11] [3.1.1] Bump version. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 414c9b29a..2192a1593 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ termit - 3.1.0 + 3.1.1 TermIt Terminology manager based on Semantic Web technologies. ${packaging}