From 2d45297acd546d84583c750b6031f63843adf62f Mon Sep 17 00:00:00 2001
From: BVier <26220150+BVier@users.noreply.github.com>
Date: Wed, 17 Jan 2018 13:55:23 +0100
Subject: [PATCH] TSK-83: delete Classification (with tests)
---
.../pro/taskana/ClassificationService.java | 16 +++
.../ClassificationInUseException.java | 13 +++
.../impl/ClassificationServiceImpl.java | 35 +++++++
.../pro/taskana/impl/TaskServiceImpl.java | 6 +-
.../model/mappings/ClassificationMapper.java | 46 ++++-----
.../taskana/model/mappings/TaskMapper.java | 6 ++
.../DeleteClassificationAccTest.java | 97 ++++++++++++-------
.../src/test/resources/sql/classification.sql | 2 +-
8 files changed, 155 insertions(+), 66 deletions(-)
create mode 100644 lib/taskana-core/src/main/java/pro/taskana/exceptions/ClassificationInUseException.java
diff --git a/lib/taskana-core/src/main/java/pro/taskana/ClassificationService.java b/lib/taskana-core/src/main/java/pro/taskana/ClassificationService.java
index df0561db0..af52f522d 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/ClassificationService.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/ClassificationService.java
@@ -3,6 +3,7 @@ package pro.taskana;
import java.util.List;
import pro.taskana.exceptions.ClassificationAlreadyExistException;
+import pro.taskana.exceptions.ClassificationInUseException;
import pro.taskana.exceptions.ClassificationNotFoundException;
/**
@@ -44,6 +45,21 @@ public interface ClassificationService {
*/
Classification getClassification(String key, String domain) throws ClassificationNotFoundException;
+ /**
+ * Delete a classification with all child classifications.
+ *
+ * @param classificationKey
+ * the key of the classification you want to delete.
+ * @param domain
+ * the domains for which you want to delete the classification.
+ * if "", the function tries to delete the "master domain" classification and any other classification with this key.
+ * @throws ClassificationInUseException
+ * if there are Task existing, which refer to this classification.
+ * @throws ClassificationNotFoundException
+ * if for an domain no classification specification is found.
+ */
+ void deleteClassification(String classificationKey, String domain) throws ClassificationInUseException, ClassificationNotFoundException;
+
/**
* Persists a new classification after adding default values.
* The classification will be added to root-domain, too - if not already existing.
diff --git a/lib/taskana-core/src/main/java/pro/taskana/exceptions/ClassificationInUseException.java b/lib/taskana-core/src/main/java/pro/taskana/exceptions/ClassificationInUseException.java
new file mode 100644
index 000000000..c7052f1b7
--- /dev/null
+++ b/lib/taskana-core/src/main/java/pro/taskana/exceptions/ClassificationInUseException.java
@@ -0,0 +1,13 @@
+package pro.taskana.exceptions;
+
+/**
+ * Thrown if a specific task is not in the database.
+ */
+public class ClassificationInUseException extends TaskanaException {
+
+ public ClassificationInUseException(String msg) {
+ super(msg);
+ }
+
+ private static final long serialVersionUID = 1L;
+}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java
index 74057ce3d..695db1eaf 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java
@@ -14,6 +14,7 @@ import pro.taskana.ClassificationService;
import pro.taskana.ClassificationSummary;
import pro.taskana.TaskanaEngine;
import pro.taskana.exceptions.ClassificationAlreadyExistException;
+import pro.taskana.exceptions.ClassificationInUseException;
import pro.taskana.exceptions.ClassificationNotFoundException;
import pro.taskana.exceptions.NotAuthorizedException;
import pro.taskana.exceptions.SystemException;
@@ -291,4 +292,38 @@ public class ClassificationServiceImpl implements ClassificationService {
}
return isExisting;
}
+
+ @Override
+ public void deleteClassification(String classificationKey, String domain) throws ClassificationInUseException, ClassificationNotFoundException {
+ try {
+ taskanaEngineImpl.openConnection();
+ if (this.classificationMapper.findByKeyAndDomain(classificationKey, domain) == null) {
+ throw new ClassificationNotFoundException("The classification " + classificationKey + "wasn't found in the domain " + domain);
+ }
+
+ if (domain.equals("")) {
+ //master mode - delete all associated classifications in every domain.
+ List domains = this.classificationMapper.getDomainsForClassification(classificationKey);
+ domains.remove("");
+ for (String classificationDomain : domains) {
+ deleteClassification(classificationKey, classificationDomain);
+ }
+ }
+
+ TaskServiceImpl taskService = (TaskServiceImpl) taskanaEngineImpl.getTaskService();
+ int countTasks = taskService.countTasksByClassificationAndDomain(classificationKey, domain);
+ if (countTasks > 0) {
+ throw new ClassificationInUseException("There are " + countTasks + " Tasks which belong to this classification or a child classification. Please complete them and try again.");
+ }
+
+ List childKeys = this.classificationMapper.getChildrenOfClassification(classificationKey, domain);
+ for (String key : childKeys) {
+ this.deleteClassification(key, domain);
+ }
+
+ this.classificationMapper.deleteClassificationInDomain(classificationKey, domain);
+ } finally {
+ taskanaEngineImpl.returnConnection();
+ }
+ }
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java
index 61fda7ae0..72ad7109e 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java
@@ -835,9 +835,9 @@ public class TaskServiceImpl implements TaskService {
}
}
- private void initAttachment(AttachmentImpl attachment, Task newTask) {
- if (attachment.getId() == null) {
- attachment.setId(IdGenerator.generateWithPrefix(ID_PREFIX_ATTACHMENT));
+ public int countTasksByClassificationAndDomain(String classificationKey, String domain) {
+ return taskMapper.countTasksByClassificationAndDomain(classificationKey, domain);
+ }
}
if (attachment.getCreated() == null) {
attachment.setCreated(Instant.now());
diff --git a/lib/taskana-core/src/main/java/pro/taskana/model/mappings/ClassificationMapper.java b/lib/taskana-core/src/main/java/pro/taskana/model/mappings/ClassificationMapper.java
index 03c113e4c..2de384a18 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/model/mappings/ClassificationMapper.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/model/mappings/ClassificationMapper.java
@@ -2,6 +2,7 @@ package pro.taskana.model.mappings;
import java.util.List;
+import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
@@ -51,6 +52,11 @@ public interface ClassificationMapper {
value = "UPDATE CLASSIFICATION SET KEY = #{classification.key}, PARENT_CLASSIFICATION_KEY = #{classification.parentClassificationKey}, CATEGORY = #{classification.category}, TYPE = #{classification.type}, NAME = #{classification.name}, DESCRIPTION = #{classification.description}, PRIORITY = #{classification.priority}, SERVICE_LEVEL = #{classification.serviceLevel}, DOMAIN = #{classification.domain}, VALID_IN_DOMAIN = #{classification.isValidInDomain}, APPLICATION_ENTRY_POINT = #{classification.applicationEntryPoint}, CUSTOM_1 = #{classification.custom1}, CUSTOM_2 = #{classification.custom2}, CUSTOM_3 = #{classification.custom3}, CUSTOM_4 = #{classification.custom4}, CUSTOM_5 = #{classification.custom5}, CUSTOM_6 = #{classification.custom6}, CUSTOM_7 = #{classification.custom7}, CUSTOM_8 = #{classification.custom8} WHERE ID = #{classification.id}")
void update(@Param("classification") ClassificationImpl classification);
+ @Delete("DELETE FROM CLASSIFICATION "
+ + "WHERE KEY = #{classificationKey}"
+ + "AND DOMAIN = #{domain}")
+ void deleteClassificationInDomain(@Param("classificationKey") String classificationKey, @Param("domain") String domain);
+
@Select("")
+ List getDomainsForClassification(@Param("classification_key") String classificationKey);
+
+ @Select("SELECT KEY "
+ + "FROM CLASSIFICATION "
+ + "WHERE PARENT_CLASSIFICATION_KEY = #{classification_key} "
+ + "AND DOMAIN = #{domain}")
+ List getChildrenOfClassification(@Param("classification_key") String classificationKey, @Param("domain") String domain);
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/model/mappings/TaskMapper.java b/lib/taskana-core/src/main/java/pro/taskana/model/mappings/TaskMapper.java
index 0136a872f..80cf47f80 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/model/mappings/TaskMapper.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/model/mappings/TaskMapper.java
@@ -170,4 +170,10 @@ public interface TaskMapper {
@Result(property = "custom9", column = "CUSTOM_9"),
@Result(property = "custom10", column = "CUSTOM_10") })
List findTaskSummariesByWorkbasketKey(@Param("workbasketKey") String workbasketKey);
+
+ @Select("SELECT COUNT(ID) "
+ + "FROM TASK "
+ + "WHERE CLASSIFICATION_KEY = #{classificationKey} "
+ + "AND DOMAIN = #{domain}")
+ int countTasksByClassificationAndDomain(@Param("classificationKey") String classificationKey, @Param("domain") String domain);
}
diff --git a/lib/taskana-core/src/test/java/acceptance/classification/DeleteClassificationAccTest.java b/lib/taskana-core/src/test/java/acceptance/classification/DeleteClassificationAccTest.java
index a1bbba98f..6bd15465a 100644
--- a/lib/taskana-core/src/test/java/acceptance/classification/DeleteClassificationAccTest.java
+++ b/lib/taskana-core/src/test/java/acceptance/classification/DeleteClassificationAccTest.java
@@ -5,17 +5,15 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.sql.SQLException;
-import java.util.List;
import org.h2.store.fs.FileUtils;
import org.junit.AfterClass;
-import org.junit.Ignore;
import org.junit.Test;
import acceptance.AbstractAccTest;
import pro.taskana.Classification;
import pro.taskana.ClassificationService;
-import pro.taskana.ClassificationSummary;
+import pro.taskana.exceptions.ClassificationInUseException;
import pro.taskana.exceptions.ClassificationNotFoundException;
import pro.taskana.exceptions.NotAuthorizedException;
@@ -24,54 +22,85 @@ import pro.taskana.exceptions.NotAuthorizedException;
*/
public class DeleteClassificationAccTest extends AbstractAccTest {
+ private ClassificationService classificationService;
+
public DeleteClassificationAccTest() {
super();
+ classificationService = taskanaEngine.getClassificationService();
}
- @Ignore
@Test
public void testDeleteClassificationInDomain()
- throws SQLException, ClassificationNotFoundException, NotAuthorizedException {
- ClassificationService classificationService = taskanaEngine.getClassificationService();
- // classificationService.deleteClassification("L140101", "DOMAIN_A");
+ throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ClassificationInUseException {
+ classificationService.deleteClassification("L140101", "DOMAIN_A");
Classification classification = classificationService.getClassification("L140101", "DOMAIN_A");
assertNotNull(classification);
assertEquals("", classification.getDomain());
- List classifications = classificationService.getAllClassifications("L140101",
- "DOMAIN_A");
- ClassificationSummary temp = classifications.get(classifications.size() - 1);
- classification = classificationService.getClassification(temp.getKey(), temp.getDomain());
+ classification = classificationService.getClassification("L140101", "DOMAIN_A");
+ assertTrue(classification.getDomain() == "");
+ assertTrue("DOMAIN_A" != classification.getDomain());
+ }
+
+ @Test (expected = ClassificationInUseException.class)
+ public void testThrowExeptionIfDeleteClassificationWithExistingTasks()
+ throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ClassificationInUseException {
+ classificationService.deleteClassification("L1050", "DOMAIN_A");
+ }
+
+ @Test (expected = ClassificationInUseException.class)
+ public void testThrowExeptionIfDeleteMasterClassificationWithExistingTasks()
+ throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ClassificationInUseException {
+ classificationService.deleteClassification("L1050", "");
}
- @Ignore
@Test
- public void testDeleteClassificationFromRootDomain()
- throws SQLException, ClassificationNotFoundException, NotAuthorizedException {
- ClassificationService classificationService = taskanaEngine.getClassificationService();
- // classificationService.deleteClassification("L1050", "DOMAIN_A");
- // classificationService.deleteClassification("L1050", "");
+ public void testDeleteMasterClassification()
+ throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ClassificationInUseException {
+ classificationService.deleteClassification("L12010", "");
- Classification classification = classificationService.getClassification("L140101", "DOMAIN_A");
- assertTrue(classification == null);
+ boolean classificationNotFound = false;
+ try {
+ classificationService.getClassification("L12010", "DOMAIN_A");
+ } catch (ClassificationNotFoundException e) {
+ classificationNotFound = true;
+ }
+ assertTrue(classificationNotFound);
}
- // @Ignore
- // @Test(expected = ClassificationInUseException.class)
- // public void testGetExceptionIfDeletedClassificationFromRootDomainIsStillUsedInDomain()
- // throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ClassificationInUseException {
- // ClassificationService classificationService = taskanaEngine.getClassificationService();
- // classificationService.deleteClassification("L10000", "");
- // }
- //
- // @Ignore
- // @Test(expected = ClassificationInUseException.class)
- // public void testGetExceptionIfDeletedClassificationIsStillUsedInTask()
- // throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ClassificationInUseException {
- // ClassificationService classificationService = taskanaEngine.getClassificationService();
- // classificationService.deleteClassification("L10000", "DOMAIN_A");
- // }
+ @Test
+ public void testThrowExceptionWhenChildClassificationIsInUseAndRollback()
+ throws ClassificationInUseException, NotAuthorizedException, ClassificationNotFoundException {
+ boolean classificationInUse = false;
+ try {
+ classificationService.deleteClassification("L11010", "DOMAIN_A");
+ } catch (ClassificationInUseException e) {
+ classificationInUse = true;
+ }
+ assertTrue(classificationInUse);
+ classificationService.getClassification("L11010", "DOMAIN_A");
+
+ classificationInUse = false;
+ try {
+ classificationService.deleteClassification("L11010", "");
+ } catch (ClassificationInUseException e) {
+ classificationInUse = true;
+ }
+ assertTrue(classificationInUse);
+ classificationService.getClassification("L11010", "");
+ classificationService.getClassification("L11010", "DOMAIN_A");
+ }
+
+ @Test(expected = ClassificationNotFoundException.class)
+ public void testThrowClassificationNotFoundIfClassificationNotExists() throws ClassificationNotFoundException, ClassificationInUseException {
+ classificationService.deleteClassification("not existing classification key", "");
+ }
+
+ @Test(expected = ClassificationNotFoundException.class)
+ public void testThrowClassificationNotFoundIfClassificationNotExistsInDomain() throws ClassificationNotFoundException, ClassificationInUseException {
+ classificationService.deleteClassification("L10000", "DOMAIN_B");
+ }
@AfterClass
public static void cleanUpClass() {
diff --git a/lib/taskana-core/src/test/resources/sql/classification.sql b/lib/taskana-core/src/test/resources/sql/classification.sql
index 76a7bf0e4..75ea9fd5d 100644
--- a/lib/taskana-core/src/test/resources/sql/classification.sql
+++ b/lib/taskana-core/src/test/resources/sql/classification.sql
@@ -24,7 +24,7 @@ INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000008', 'L
INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000009', 'L140101', '', 'EXTERN', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, 'Zustimmungserklärung', 'Zustimmungserklärung', 2, 'P2D', '', 'VNR', '', '', '', '', '', '', '');
INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000010', 'T2100', '', 'MANUAL', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, 'T-Vertragstermin VERA', 'T-Vertragstermin VERA', 2, 'P2D', '', 'VNR', '', '', '', '', '', '', '');
INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000011', 'T6310', '', 'AUTOMATIC', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, 'T-GUK Honorarrechnung erstellen', 'Generali Unterstützungskasse Honorar wird fällig', 2, 'P2D', '', 'VNR', '', '', '', '', '', '', '');
-INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000013', 'DOCTYPE_DEFAULT', '', 'EXTERN', 'DOCUMENT', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, 'EP allgemein', 'EP allgemein', 99, 'P2000D', '', 'VNR', '', '', '', '', '', '', '');
+INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000013', 'DOKTYP_DEFAULT', '', 'EXTERN', 'DOCUMENT', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, 'EP allgemein', 'EP allgemein', 99, 'P2000D', '', 'VNR', '', '', '', '', '', '', '');
INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000014', 'L10000', '', 'EXTERN', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, 'BUZ-Leistungsfall', 'BUZ-Leistungsfall', 1, 'P1D', '', 'VNR,RVNR,KOLVNR', '', '', '', '', '', '', '');
INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000016', 'T2000', '', 'MANUAL', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, 'T-Vertragstermin', 'T-Vertragstermin', 1, 'P1D', '', 'VNR,RVNR,KOLVNR', '', '', '', '', '', '', '');