From 3d9e04c311c6708efa39742002781f28f2c6d133 Mon Sep 17 00:00:00 2001 From: veltrup Date: Tue, 24 May 2022 14:30:12 +0200 Subject: [PATCH] refactor: use long as id, and more supplements --- pmd-ruleset.xml | 8 +- pom.xml | 22 ++- spotbug-exclude-filter.xml | 2 +- .../core/domain/entity/EntityLock.java | 18 ++- .../core/domain/entity/RecycleBinItem.java | 26 ++-- .../core/domain/exception/EntityNotFound.java | 14 +- .../core/domain/exception/GroupNotEmpty.java | 22 +++ .../core/port/AccessControl.java | 18 ++- .../core/port/ContentRepository.java | 10 +- .../core/port/EntityLockManager.java | 7 +- .../core/port/HistoryManager.java | 7 +- .../core/port/IdGenerator.java | 2 +- .../core/port/Publisher.java | 6 +- .../core/port/RecycleBin.java | 5 +- .../core/port/SearchIndex.java | 3 +- .../core/port/VersioningManager.java | 5 +- .../core/usecase/PurgeEntity.java | 31 ++--- .../core/usecase/PurgeGroup.java | 87 ++++++++++++ .../core/usecase/RecoverEntity.java | 11 +- .../core/usecase/RemoveEntity.java | 66 +++++++-- .../core/usecase/StoreEntity.java | 22 +-- src/main/java/module-info.java | 1 + .../core/usecase/PurgeEntityTest.java | 129 ++++++++++++++++++ 23 files changed, 404 insertions(+), 118 deletions(-) create mode 100644 src/main/java/com/sitepark/ies/contentrepository/core/domain/exception/GroupNotEmpty.java create mode 100644 src/main/java/com/sitepark/ies/contentrepository/core/usecase/PurgeGroup.java create mode 100644 src/test/java/com/sitepark/ies/contentrepository/core/usecase/PurgeEntityTest.java diff --git a/pmd-ruleset.xml b/pmd-ruleset.xml index 8869e21..ef18056 100644 --- a/pmd-ruleset.xml +++ b/pmd-ruleset.xml @@ -36,7 +36,13 @@ --> - + + + + + + diff --git a/pom.xml b/pom.xml index e774a36..35776f2 100644 --- a/pom.xml +++ b/pom.xml @@ -15,11 +15,24 @@ + 5.8.2 4.6.0 UTF-8 11 + + + + org.junit + junit-bom + ${junit.version} + pom + import + + + + @@ -56,19 +69,16 @@ org.junit.jupiter junit-jupiter-api - 5.6.2 test org.junit.jupiter junit-jupiter-engine - 5.6.2 test org.junit.platform junit-platform-runner - 1.6.2 test @@ -77,6 +87,12 @@ 1.3 test + + org.mockito + mockito-core + 4.5.1 + test + diff --git a/spotbug-exclude-filter.xml b/spotbug-exclude-filter.xml index e2e4b22..de9f2df 100644 --- a/spotbug-exclude-filter.xml +++ b/spotbug-exclude-filter.xml @@ -8,7 +8,7 @@ + pattern="REC_CATCH_EXCEPTION,RV_CHECK_FOR_POSITIVE_INDEXOF,BC_UNCONFIRMED_CAST_OF_RETURN_VALUE,THROWS_METHOD_THROWS_CLAUSE_THROWABLE" /> diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/domain/entity/EntityLock.java b/src/main/java/com/sitepark/ies/contentrepository/core/domain/entity/EntityLock.java index 6f11117..6761965 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/domain/entity/EntityLock.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/domain/entity/EntityLock.java @@ -4,8 +4,8 @@ public final class EntityLock implements Serializable { - private final Identifier entity; - private final Identifier user; + private final long entity; + private final long user; private final long created; private final long lastAccess; private final long ttl; @@ -20,11 +20,11 @@ private EntityLock(Builder builder) { this.ttl = builder.ttl; } - public Identifier getEntity() { + public long getEntity() { return entity; } - public Identifier getUser() { + public long getUser() { return user; } @@ -55,8 +55,8 @@ public String toString() { public static class Builder { - private Identifier entity; - private Identifier user; + private long entity; + private long user; private long created; private long lastAccess; private long ttl; @@ -72,14 +72,12 @@ private Builder(EntityLock entityLock) { this.ttl = entityLock.ttl; } - public Builder entity(Identifier entity) { - assert entity != null; + public Builder entity(long entity) { this.entity = entity; return this; } - public Builder user(Identifier user) { - assert user != null; + public Builder user(long user) { this.user = user; return this; } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/domain/entity/RecycleBinItem.java b/src/main/java/com/sitepark/ies/contentrepository/core/domain/entity/RecycleBinItem.java index 96abdb3..ea8e2ce 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/domain/entity/RecycleBinItem.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/domain/entity/RecycleBinItem.java @@ -6,23 +6,23 @@ public final class RecycleBinItem { - private final Identifier identifier; - private final Identifier parent; + private final long id; + private final long parent; private final Entity entity; private final List children; private RecycleBinItem(Builder builder) { - this.identifier = builder.identifier; + this.id = builder.id; this.parent = builder.parent; this.entity = builder.entity; this.children = builder.children; } - public Identifier getIdentifier() { - return this.identifier; + public long getId() { + return this.id; } - public Identifier getParent() { + public long getParent() { return this.parent; } @@ -44,27 +44,25 @@ public Builder toBuilder() { public static class Builder { - private Identifier identifier; - private Identifier parent; + private long id; + private long parent; private Entity entity; private List children = new ArrayList<>(); private Builder() {} private Builder(RecycleBinItem recycleBinItem) { - this.identifier = recycleBinItem.identifier; + this.id = recycleBinItem.id; this.parent = recycleBinItem.parent; this.entity = recycleBinItem.entity; this.children = new ArrayList<>(recycleBinItem.children); } - public Builder identifier(Identifier identifier) { - assert identifier != null; - this.identifier = identifier; + public Builder identifier(long id) { + this.id = id; return this; } - public Builder parent(Identifier parent) { - assert parent != null; + public Builder parent(long parent) { this.parent = parent; return this; } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/domain/exception/EntityNotFound.java b/src/main/java/com/sitepark/ies/contentrepository/core/domain/exception/EntityNotFound.java index de5426d..d2849d1 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/domain/exception/EntityNotFound.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/domain/exception/EntityNotFound.java @@ -1,24 +1,22 @@ package com.sitepark.ies.contentrepository.core.domain.exception; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; - public class EntityNotFound extends ContentRepositoryException { private static final long serialVersionUID = 1L; - private final Identifier identifier; + private final long id; - public EntityNotFound(Identifier identifier) { + public EntityNotFound(long id) { super(); - this.identifier = identifier; + this.id = id; } - public Identifier getIdentifier() { - return this.identifier; + public long getId() { + return this.id; } @Override public String getMessage() { - return "Entity with identifier " + this.identifier + " not found"; + return "Entity with id " + this.id + " not found"; } } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/domain/exception/GroupNotEmpty.java b/src/main/java/com/sitepark/ies/contentrepository/core/domain/exception/GroupNotEmpty.java new file mode 100644 index 0000000..8c69839 --- /dev/null +++ b/src/main/java/com/sitepark/ies/contentrepository/core/domain/exception/GroupNotEmpty.java @@ -0,0 +1,22 @@ +package com.sitepark.ies.contentrepository.core.domain.exception; + +public class GroupNotEmpty extends ContentRepositoryException { + private static final long serialVersionUID = 1L; + + private final long id; + + public GroupNotEmpty(long id) { + super(); + this.id = id; + } + + public long getId() { + return this.id; + } + + @Override + public String getMessage() { + return "Group with id " + this.id + " not empty"; + } + +} \ No newline at end of file diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/AccessControl.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/AccessControl.java index bbc8b5d..9fd14ea 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/AccessControl.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/AccessControl.java @@ -1,16 +1,14 @@ package com.sitepark.ies.contentrepository.core.port; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; - public interface AccessControl { - boolean isEntityCreateable(Identifier parent); - boolean isEntityReadable(Identifier identifier); - boolean isEntityWritable(Identifier identifier); - boolean isEntityRemovable(Identifier identifier); + boolean isEntityCreateable(long parent); + boolean isEntityReadable(long id); + boolean isEntityWritable(long id); + boolean isEntityRemovable(long id); - boolean isGroupCreateable(Identifier parent); - boolean isGroupReadable(Identifier identifier); - boolean isGroupWritable(Identifier identifier); - boolean isGroupRemoveable(Identifier identifier); + boolean isGroupCreateable(long parent); + boolean isGroupReadable(long id); + boolean isGroupWritable(long id); + boolean isGroupRemoveable(long id); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/ContentRepository.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/ContentRepository.java index 691fb34..2faf0f3 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/ContentRepository.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/ContentRepository.java @@ -8,9 +8,13 @@ import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; public interface ContentRepository { + boolean isGroup(long id); + boolean isEmptyGroup(long id); Optional store(Entity entity); - Optional get(Identifier identifier); - Optional remove(Identifier identifier); + Optional get(long id); + void removeEntity(long id); + void removeGroup(long id); Optional resolveAnchor(Anchor anchor); - List getAllMediaReferences(Identifier identifier); + long resolve(Identifier identifier); + List getAllMediaReferences(long id); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/EntityLockManager.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/EntityLockManager.java index 0e47b66..067c7bd 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/EntityLockManager.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/EntityLockManager.java @@ -4,11 +4,10 @@ import java.util.Optional; import com.sitepark.ies.contentrepository.core.domain.entity.EntityLock; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; public interface EntityLockManager { - Optional getLock(Identifier identifier); - void lock(Identifier identifier); - void unlock(Identifier identifier); + Optional getLock(long id); + void lock(long id); + void unlock(long id); List getLockList(); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/HistoryManager.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/HistoryManager.java index 14ec3f5..72876c1 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/HistoryManager.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/HistoryManager.java @@ -4,10 +4,9 @@ import com.sitepark.ies.contentrepository.core.domain.entity.HistoryEntry; import com.sitepark.ies.contentrepository.core.domain.entity.HistoryEntryType; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; public interface HistoryManager { - void purge(Identifier identifier); - HistoryEntry createEntry(Identifier identifier, long timestamp, HistoryEntryType type); - List getHistory(Identifier identifier); + void purge(long id); + HistoryEntry createEntry(long id, long timestamp, HistoryEntryType type); + List getHistory(long id); } \ No newline at end of file diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/IdGenerator.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/IdGenerator.java index b220ad8..641ce56 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/IdGenerator.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/IdGenerator.java @@ -1,5 +1,5 @@ package com.sitepark.ies.contentrepository.core.port; public interface IdGenerator { - Long generate(); + long generate(); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/Publisher.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/Publisher.java index 4d993df..062b837 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/Publisher.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/Publisher.java @@ -1,8 +1,6 @@ package com.sitepark.ies.contentrepository.core.port; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; - public interface Publisher { - void republish(Identifier identifier, long version); - void depublish(Identifier identifier); + void republish(long id, long version); + void depublish(long id); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/RecycleBin.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/RecycleBin.java index 46a21b6..db51cca 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/RecycleBin.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/RecycleBin.java @@ -3,13 +3,12 @@ import java.util.List; import java.util.Optional; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; import com.sitepark.ies.contentrepository.core.domain.entity.RecycleBinItem; import com.sitepark.ies.contentrepository.core.domain.entity.RecycleBinItemFilter; public interface RecycleBin { - Optional get(Identifier identifier); + Optional get(long id); void add(RecycleBinItem item); - void remove(Identifier identifier); + void removeByObject(long id); List find(RecycleBinItemFilter filter); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/SearchIndex.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/SearchIndex.java index 0feab61..1ce3f55 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/SearchIndex.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/SearchIndex.java @@ -1,9 +1,8 @@ package com.sitepark.ies.contentrepository.core.port; import com.sitepark.ies.contentrepository.core.domain.entity.Entity; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; public interface SearchIndex { void index(Entity entity); - void remove(Identifier identifier); + void remove(long id); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/port/VersioningManager.java b/src/main/java/com/sitepark/ies/contentrepository/core/port/VersioningManager.java index 4b1bfd9..6b66ed4 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/port/VersioningManager.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/port/VersioningManager.java @@ -4,15 +4,14 @@ import com.sitepark.ies.contentrepository.core.domain.entity.Entity; import com.sitepark.ies.contentrepository.core.domain.entity.EntityVersion; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; public interface VersioningManager { - void removeAllVersions(Identifier identifier); + void removeAllVersions(long id); Entity createNewVersion(Entity entity); Entity revertToVersion(EntityVersion version); Entity getVersion(EntityVersion version); Entity getNextVersionSince(long timestamp); - List getAllMediaReferences(Identifier identifier); + List getAllMediaReferences(long id); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/PurgeEntity.java b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/PurgeEntity.java index 024e1b7..accbecd 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/PurgeEntity.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/PurgeEntity.java @@ -6,10 +6,7 @@ import javax.inject.Inject; -import org.eclipse.jdt.annotation.NonNull; - import com.sitepark.ies.contentrepository.core.domain.entity.EntityLock; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; import com.sitepark.ies.contentrepository.core.domain.exception.AccessDenied; import com.sitepark.ies.contentrepository.core.domain.exception.EntityLocked; import com.sitepark.ies.contentrepository.core.port.AccessControl; @@ -50,34 +47,30 @@ protected PurgeEntity(ContentRepository repository, EntityLockManager lockManage this.publisher = publisher; } - public void purge(@NonNull Identifier identifier) { - - if (identifier == null) { - throw new IllegalArgumentException("identifier is null"); - } + public void purgeEntity(long id) { - if (!this.accessControl.isEntityRemovable(identifier)) { - throw new AccessDenied("Not allowed to remove entity " + identifier); + if (!this.accessControl.isEntityRemovable(id)) { + throw new AccessDenied("Not allowed to remove entity " + id); } - Optional lock = this.lockManager.getLock(identifier); + Optional lock = this.lockManager.getLock(id); lock.ifPresent(l -> { throw new EntityLocked(l); }); - this.searchIndex.remove(identifier); + this.searchIndex.remove(id); - this.publisher.depublish(identifier); + this.publisher.depublish(id); - List mediaRefs = this.repository.getAllMediaReferences(identifier); - this.repository.remove(identifier); + List mediaRefs = this.repository.getAllMediaReferences(id); + this.repository.removeEntity(id); - this.historyManager.purge(identifier); + this.historyManager.purge(id); - List mediaRefsFromOtherVersions = this.versioningManager.getAllMediaReferences(identifier); - this.versioningManager.removeAllVersions(identifier); + List mediaRefsFromOtherVersions = this.versioningManager.getAllMediaReferences(id); + this.versioningManager.removeAllVersions(id); - this.recycleBin.remove(identifier); + this.recycleBin.removeByObject(id); List allMediaRefs = new ArrayList<>(); allMediaRefs.addAll(mediaRefs); diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/PurgeGroup.java b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/PurgeGroup.java new file mode 100644 index 0000000..5e7b51b --- /dev/null +++ b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/PurgeGroup.java @@ -0,0 +1,87 @@ +package com.sitepark.ies.contentrepository.core.usecase; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import javax.inject.Inject; + +import com.sitepark.ies.contentrepository.core.domain.entity.EntityLock; +import com.sitepark.ies.contentrepository.core.domain.exception.AccessDenied; +import com.sitepark.ies.contentrepository.core.domain.exception.EntityLocked; +import com.sitepark.ies.contentrepository.core.domain.exception.GroupNotEmpty; +import com.sitepark.ies.contentrepository.core.port.AccessControl; +import com.sitepark.ies.contentrepository.core.port.ContentRepository; +import com.sitepark.ies.contentrepository.core.port.EntityLockManager; +import com.sitepark.ies.contentrepository.core.port.HistoryManager; +import com.sitepark.ies.contentrepository.core.port.MediaRepository; +import com.sitepark.ies.contentrepository.core.port.Publisher; +import com.sitepark.ies.contentrepository.core.port.RecycleBin; +import com.sitepark.ies.contentrepository.core.port.SearchIndex; +import com.sitepark.ies.contentrepository.core.port.VersioningManager; + +public final class PurgeGroup { + + private final ContentRepository repository; + private final EntityLockManager lockManager; + private final VersioningManager versioningManager; + private final HistoryManager historyManager; + private final AccessControl accessControl; + private final RecycleBin recycleBin; + private final SearchIndex searchIndex; + private final MediaRepository mediaRepository; + private final Publisher publisher; + + @Inject + protected PurgeGroup(ContentRepository repository, EntityLockManager lockManager, + VersioningManager versioningManager, HistoryManager historyManager, AccessControl accessControl, + RecycleBin recycleBin, SearchIndex searchIndex, MediaRepository mediaRepository, Publisher publisher) { + + this.repository = repository; + this.lockManager = lockManager; + this.historyManager = historyManager; + this.versioningManager = versioningManager; + this.accessControl = accessControl; + this.recycleBin = recycleBin; + this.searchIndex = searchIndex; + this.mediaRepository = mediaRepository; + this.publisher = publisher; + } + + public void purgeGroup(long id) { + + if (!this.accessControl.isGroupRemoveable(id)) { + throw new AccessDenied("Not allowed to remove group " + id); + } + + if (!this.repository.isEmptyGroup(id)) { + throw new GroupNotEmpty(id); + } + + Optional lock = this.lockManager.getLock(id); + lock.ifPresent(l -> { + throw new EntityLocked(l); + }); + + this.searchIndex.remove(id); + + this.publisher.depublish(id); + + List mediaRefs = this.repository.getAllMediaReferences(id); + this.repository.removeGroup(id); + + this.historyManager.purge(id); + + List mediaRefsFromOtherVersions = this.versioningManager.getAllMediaReferences(id); + this.versioningManager.removeAllVersions(id); + + this.recycleBin.removeByObject(id); + + List allMediaRefs = new ArrayList<>(); + allMediaRefs.addAll(mediaRefs); + allMediaRefs.addAll(mediaRefsFromOtherVersions); + + this.mediaRepository.remove(allMediaRefs); + + } +} diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/RecoverEntity.java b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/RecoverEntity.java index 5fa8349..6bec139 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/RecoverEntity.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/RecoverEntity.java @@ -4,7 +4,6 @@ import com.sitepark.ies.contentrepository.core.domain.entity.Entity; import com.sitepark.ies.contentrepository.core.domain.entity.HistoryEntryType; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; import com.sitepark.ies.contentrepository.core.domain.entity.RecycleBinItem; import com.sitepark.ies.contentrepository.core.domain.exception.AccessDenied; import com.sitepark.ies.contentrepository.core.domain.exception.EntityNotFound; @@ -31,13 +30,13 @@ protected RecoverEntity(ContentRepository repository, HistoryManager historyMana this.searchIndex = searchIndex; } - public void recover(Identifier identifier) { + public void recover(long id) { - Optional recycleBinItem = this.recycleBin.get(identifier); - recycleBinItem.orElseThrow(() -> new EntityNotFound(identifier)); + Optional recycleBinItem = this.recycleBin.get(id); + recycleBinItem.orElseThrow(() -> new EntityNotFound(id)); if (!this.accessControl.isGroupCreateable(recycleBinItem.get().getParent())) { - throw new AccessDenied("Not allowed to recover entity " + recycleBinItem.get().getIdentifier() + throw new AccessDenied("Not allowed to recover entity " + recycleBinItem.get().getId() + " in group " + recycleBinItem.get().getParent()); } @@ -45,7 +44,7 @@ public void recover(Identifier identifier) { this.repository.store(entity); - this.historyManager.createEntry(identifier, System.currentTimeMillis(), HistoryEntryType.RESTORED); + this.historyManager.createEntry(id, System.currentTimeMillis(), HistoryEntryType.RESTORED); this.searchIndex.index(entity); } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/RemoveEntity.java b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/RemoveEntity.java index 95ca153..a1837f0 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/RemoveEntity.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/RemoveEntity.java @@ -5,14 +5,15 @@ import com.sitepark.ies.contentrepository.core.domain.entity.Entity; import com.sitepark.ies.contentrepository.core.domain.entity.EntityLock; import com.sitepark.ies.contentrepository.core.domain.entity.HistoryEntryType; -import com.sitepark.ies.contentrepository.core.domain.entity.Identifier; import com.sitepark.ies.contentrepository.core.domain.entity.RecycleBinItem; import com.sitepark.ies.contentrepository.core.domain.exception.AccessDenied; import com.sitepark.ies.contentrepository.core.domain.exception.EntityLocked; +import com.sitepark.ies.contentrepository.core.domain.exception.GroupNotEmpty; import com.sitepark.ies.contentrepository.core.port.AccessControl; import com.sitepark.ies.contentrepository.core.port.ContentRepository; import com.sitepark.ies.contentrepository.core.port.EntityLockManager; import com.sitepark.ies.contentrepository.core.port.HistoryManager; +import com.sitepark.ies.contentrepository.core.port.Publisher; import com.sitepark.ies.contentrepository.core.port.RecycleBin; import com.sitepark.ies.contentrepository.core.port.SearchIndex; @@ -24,43 +25,80 @@ public final class RemoveEntity { private final AccessControl accessControl; private final RecycleBin recycleBin; private final SearchIndex searchIndex; + private final Publisher publisher; protected RemoveEntity(ContentRepository repository, EntityLockManager lockManager, - HistoryManager historyManager, AccessControl accessControl, RecycleBin recycleBin, - SearchIndex searchIndex) { + HistoryManager historyManager, AccessControl accessControl, + RecycleBin recycleBin, SearchIndex searchIndex, Publisher publisher) { + this.repository = repository; this.lockManager = lockManager; this.historyManager = historyManager; this.accessControl = accessControl; this.recycleBin = recycleBin; this.searchIndex = searchIndex; + this.publisher = publisher; + } + + public void remove(long id) { + if (this.repository.isGroup(id)) { + this.removeGroup(id); + } else { + this.removeEntity(id); + } } - public Optional remove(Identifier identifier) { + public void removeGroup(long id) { - if (!this.accessControl.isEntityRemovable(identifier)) { - throw new AccessDenied("Not allowed to remove entity " + identifier); + if (!this.accessControl.isGroupRemoveable(id)) { + throw new AccessDenied("Not allowed to remove group " + id); } - Optional entity = this.repository.get(identifier); - if (entity.isEmpty()) { - return entity; + if (!this.repository.isEmptyGroup(id)) { + throw new GroupNotEmpty(id); } - Optional lock = this.lockManager.getLock(identifier); + Optional lock = this.lockManager.getLock(id); lock.ifPresent(l -> { throw new EntityLocked(l); }); - this.repository.remove(identifier); + this.searchIndex.remove(id); + + this.repository.removeGroup(id); - this.historyManager.createEntry(identifier, System.currentTimeMillis(), HistoryEntryType.REMOVED); + this.historyManager.createEntry(id, System.currentTimeMillis(), HistoryEntryType.REMOVED); RecycleBinItem recycleBinItem = RecycleBinItem.builder().build(); this.recycleBin.add(recycleBinItem); - this.searchIndex.remove(identifier); + } + + public void removeEntity(long id) { + + if (!this.accessControl.isEntityRemovable(id)) { + throw new AccessDenied("Not allowed to remove entity " + id); + } - return entity; + Optional entity = this.repository.get(id); + if (entity.isEmpty()) { + return; + } + + Optional lock = this.lockManager.getLock(id); + lock.ifPresent(l -> { + throw new EntityLocked(l); + }); + + this.searchIndex.remove(id); + + this.publisher.depublish(id); + + this.repository.removeEntity(id); + + this.historyManager.createEntry(id, System.currentTimeMillis(), HistoryEntryType.REMOVED); + + RecycleBinItem recycleBinItem = RecycleBinItem.builder().build(); + this.recycleBin.add(recycleBinItem); } } diff --git a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/StoreEntity.java b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/StoreEntity.java index 0f78f5f..1bd0d0f 100644 --- a/src/main/java/com/sitepark/ies/contentrepository/core/usecase/StoreEntity.java +++ b/src/main/java/com/sitepark/ies/contentrepository/core/usecase/StoreEntity.java @@ -57,16 +57,20 @@ private Identifier create(Entity newEntity) { Optional parent = newEntity.getParent(); parent.orElseThrow(() -> new ParentMissing()); - if (!this.accessControl.isEntityCreateable(parent.get())) { + long parentId = this.repository.resolve(parent.get()); + + if (!this.accessControl.isEntityCreateable(parentId)) { throw new AccessDenied("Not allowed to create entity in group " + parent); } - Entity entityWithId = newEntity.toBuilder().identifier(Identifier.ofId(this.idGenerator.generate())).build(); + long generatedId = this.idGenerator.generate(); + + Entity entityWithId = newEntity.toBuilder().identifier(Identifier.ofId(generatedId)).build(); Entity versioned = this.versioningManager.createNewVersion(entityWithId); this.repository.store(versioned); - this.historyManager.createEntry(versioned.getIdentifier().get(), versioned.getVersion().get().getTimestamp(), + this.historyManager.createEntry(generatedId, versioned.getVersion().get().getTimestamp(), HistoryEntryType.CREATED); this.searchIndex.index(versioned); @@ -78,14 +82,16 @@ private Identifier update(Entity updateEntity) { updateEntity.getIdentifier() .orElseThrow(() -> new IllegalArgumentException("Update failed, identifier missing")); - Optional existsEntity = this.repository.get(updateEntity.getIdentifier().get()); - existsEntity.orElseThrow(() -> new EntityNotFound(updateEntity.getIdentifier().get())); + long id = this.repository.resolve(updateEntity.getIdentifier().get()); + + Optional existsEntity = this.repository.get(id); + existsEntity.orElseThrow(() -> new EntityNotFound(id)); - if (!this.accessControl.isEntityWritable(updateEntity.getIdentifier().get())) { + if (!this.accessControl.isEntityWritable(id)) { throw new AccessDenied("Not allowed to update entity " + updateEntity.getIdentifier()); } - Optional lock = this.lockManager.getLock(updateEntity.getIdentifier().get()); + Optional lock = this.lockManager.getLock(id); lock.ifPresent(l -> { throw new EntityLocked(l); }); @@ -100,7 +106,7 @@ private Identifier update(Entity updateEntity) { this.repository.store(versioned); this.searchIndex.index(versioned); - this.historyManager.createEntry(versioned.getIdentifier().get(), versioned.getVersion().get().getTimestamp(), + this.historyManager.createEntry(id, versioned.getVersion().get().getTimestamp(), HistoryEntryType.UPDATED); return versioned.getIdentifier().get(); diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 11e4275..82b3689 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -2,6 +2,7 @@ exports com.sitepark.ies.contentrepository.core.domain.entity; exports com.sitepark.ies.contentrepository.core.domain.exception; exports com.sitepark.ies.contentrepository.core.port; + exports com.sitepark.ies.contentrepository.core.usecase; requires javax.inject; requires org.eclipse.jdt.annotation; } \ No newline at end of file diff --git a/src/test/java/com/sitepark/ies/contentrepository/core/usecase/PurgeEntityTest.java b/src/test/java/com/sitepark/ies/contentrepository/core/usecase/PurgeEntityTest.java new file mode 100644 index 0000000..2e44df7 --- /dev/null +++ b/src/test/java/com/sitepark/ies/contentrepository/core/usecase/PurgeEntityTest.java @@ -0,0 +1,129 @@ +package com.sitepark.ies.contentrepository.core.usecase; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; +import org.mockito.InOrder; + +import com.sitepark.ies.contentrepository.core.domain.entity.EntityLock; +import com.sitepark.ies.contentrepository.core.domain.exception.AccessDenied; +import com.sitepark.ies.contentrepository.core.domain.exception.EntityLocked; +import com.sitepark.ies.contentrepository.core.port.AccessControl; +import com.sitepark.ies.contentrepository.core.port.ContentRepository; +import com.sitepark.ies.contentrepository.core.port.EntityLockManager; +import com.sitepark.ies.contentrepository.core.port.HistoryManager; +import com.sitepark.ies.contentrepository.core.port.MediaRepository; +import com.sitepark.ies.contentrepository.core.port.Publisher; +import com.sitepark.ies.contentrepository.core.port.RecycleBin; +import com.sitepark.ies.contentrepository.core.port.SearchIndex; +import com.sitepark.ies.contentrepository.core.port.VersioningManager; + +class PurgeEntityTest { + + @Test + void testAccessDenied() { + + AccessControl accessControl = mock(AccessControl.class); + when(accessControl.isEntityRemovable(anyLong())).thenReturn(false); + + var purgeEntity = new PurgeEntity( + null, + null, + null, + null, + accessControl, + null, + null, + null, + null); + assertThrows(AccessDenied.class, () -> { + purgeEntity.purgeEntity(10L); + }); + } + + @Test + void testEntityIsLocked() { + + AccessControl accessControl = mock(AccessControl.class); + when(accessControl.isEntityRemovable(anyLong())).thenReturn(true); + + EntityLockManager lockManager = mock(EntityLockManager.class); + when(lockManager.getLock(anyLong())) + .thenReturn( + Optional.of( + EntityLock.builder().entity(10L).build() + ) + ); + + var purgeEntity = new PurgeEntity( + null, + lockManager, + null, + null, + accessControl, + null, + null, + null, + null); + EntityLocked entityLocked = assertThrows(EntityLocked.class, () -> { + purgeEntity.purgeEntity(10L); + }, "entity should be locked"); + assertEquals(10L, entityLocked.getLock().getEntity(), "unexpected entity id"); + } + + @SuppressWarnings("PMD") + @Test + void testPurge() { + + AccessControl accessControl = mock(AccessControl.class); + when(accessControl.isEntityRemovable(anyLong())).thenReturn(true); + + ContentRepository repository = mock(ContentRepository.class); + EntityLockManager lockManager = mock(EntityLockManager.class); + VersioningManager versioningManager = mock(VersioningManager.class); + HistoryManager historyManager = mock(HistoryManager.class); + + RecycleBin recycleBin = mock(RecycleBin.class); + SearchIndex searchIndex = mock(SearchIndex.class); + MediaRepository mediaRepository = mock(MediaRepository.class); + Publisher publisher = mock(Publisher.class); + + PurgeEntity purgeEntity = new PurgeEntity( + repository, + lockManager, + versioningManager, + historyManager, + accessControl, + recycleBin, + searchIndex, + mediaRepository, + publisher); + purgeEntity.purgeEntity(10L); + + InOrder inOrder = inOrder( + searchIndex, + publisher, + repository, + historyManager, + versioningManager, + recycleBin, + mediaRepository + ); + + inOrder.verify(searchIndex).remove(10L); + inOrder.verify(publisher).depublish(10L); + inOrder.verify(repository).removeEntity(10L); + inOrder.verify(historyManager).purge(10L); + inOrder.verify(versioningManager).removeAllVersions(10L); + inOrder.verify(recycleBin).removeByObject(10L); + inOrder.verify(mediaRepository).remove(anyList()); + } +}