From 967e59e012f94e116f2b327b6c426f44ae1bcbee Mon Sep 17 00:00:00 2001 From: ryzheboka <25465835+ryzheboka@users.noreply.github.com> Date: Tue, 18 Jan 2022 15:53:58 +0100 Subject: [PATCH] TSK-1800: add secondary object references --- .../sql/sample-data/object-reference.sql | 7 +- .../sql/test-data/object-reference.sql | 6 +- .../common/internal/util/IdGenerator.java | 1 + .../resources/sql/db2/taskana-schema-db2.sql | 620 ++++++++-------- ...kana_schema_update_4.11.0_to_5.0.0_db2.sql | 2 + .../resources/sql/h2/taskana-schema-h2.sql | 545 +++++++------- ...skana_schema_update_4.11.0_to_5.0.0_h2.sql | 2 +- .../sql/postgres/taskana-schema-postgres.sql | 669 +++++++++--------- ...schema_update_4.11.0_to_5.0.0_postgres.sql | 2 + .../test/java/acceptance/AbstractAccTest.java | 3 +- .../pro/taskana/example/ExampleBootstrap.java | 8 +- .../taskana/TaskanaCdiTestRestController.java | 4 +- .../src/test/java/pro/taskana/TaskanaEjb.java | 8 +- .../common/internal/TaskanaEngineImpl.java | 1 + .../java/pro/taskana/task/api/TaskQuery.java | 44 ++ .../taskana/task/api/TaskQueryColumnName.java | 11 +- .../pro/taskana/task/api/TaskService.java | 20 +- .../ObjectReferencePersistenceException.java | 42 ++ .../task/api/models/ObjectReference.java | 199 +++--- .../pro/taskana/task/api/models/Task.java | 64 +- .../taskana/task/api/models/TaskSummary.java | 138 ++-- .../task/internal/AttachmentHandler.java | 4 +- .../task/internal/AttachmentMapper.java | 28 +- .../task/internal/ObjectReferenceHandler.java | 164 +++++ .../task/internal/ObjectReferenceMapper.java | 62 +- .../pro/taskana/task/internal/TaskMapper.java | 10 +- .../taskana/task/internal/TaskQueryImpl.java | 137 +++- .../task/internal/TaskQueryMapper.java | 20 +- .../task/internal/TaskQuerySqlProvider.java | 51 ++ .../task/internal/TaskServiceImpl.java | 84 ++- .../builder/ObjectReferenceBuilder.java | 3 +- .../task/internal/builder/TaskBuilder.java | 10 +- .../models/AttachmentSummaryImpl.java | 10 + .../internal/models/ObjectReferenceImpl.java | 165 +++++ .../task/internal/models/TaskImpl.java | 3 + .../task/internal/models/TaskSummaryImpl.java | 78 ++ .../test/java/acceptance/AbstractAccTest.java | 5 +- .../test/java/acceptance/TaskTestMapper.java | 10 +- .../builder/ObjectReferenceBuilderTest.java | 5 +- .../acceptance/task/CreateTaskAccTest.java | 6 +- .../task/CreateTaskWithSorAccTest.java | 176 +++++ .../task/DeleteTaskWithSorAccTest.java | 123 ++++ .../task/GetTaskWithSorAccTest.java | 91 +++ .../acceptance/task/TaskModelsCloneTest.java | 6 +- .../acceptance/task/TaskQueryImplAccTest.java | 527 ++++++++++++++ .../acceptance/task/UpdateTaskAccTest.java | 6 +- .../task/UpdateTaskWithSorAccTest.java | 169 +++++ .../pro/taskana/example/ExampleBootstrap.java | 7 +- .../example/TaskanaTransactionIntTest.java | 3 +- .../transaction/TaskanaComponent.java | 8 +- .../rest/JsonPropertyEditorRegistrator.java | 3 +- .../pro/taskana/task/rest/TaskController.java | 12 +- .../task/rest/TaskQueryFilterParameter.java | 143 ++++ ...ReferenceRepresentationModelAssembler.java | 5 +- .../TaskRepresentationModelAssembler.java | 8 + ...skSummaryRepresentationModelAssembler.java | 8 + .../ObjectReferenceRepresentationModel.java | 11 + .../TaskSummaryRepresentationModel.java | 11 + .../task/rest/TaskControllerIntTest.java | 138 ++++ .../task/rest/TaskControllerRestDocTest.java | 5 +- ...hmentRepresentationModelAssemblerTest.java | 6 +- ...mmaryRepresentationModelAssemblerTest.java | 6 +- ...renceRepresentationModelAssemblerTest.java | 3 +- .../TaskRepresentationModelAssemblerTest.java | 6 +- ...mmaryRepresentationModelAssemblerTest.java | 8 +- .../java/pro/taskana/AbstractAccTest.java | 3 +- .../task-details/task-details.component.ts | 7 +- web/src/app/workplace/models/task.ts | 2 +- 68 files changed, 3538 insertions(+), 1214 deletions(-) create mode 100644 lib/taskana-core/src/main/java/pro/taskana/task/api/exceptions/ObjectReferencePersistenceException.java create mode 100644 lib/taskana-core/src/main/java/pro/taskana/task/internal/ObjectReferenceHandler.java create mode 100644 lib/taskana-core/src/main/java/pro/taskana/task/internal/models/ObjectReferenceImpl.java create mode 100644 lib/taskana-core/src/test/java/acceptance/task/CreateTaskWithSorAccTest.java create mode 100644 lib/taskana-core/src/test/java/acceptance/task/DeleteTaskWithSorAccTest.java create mode 100644 lib/taskana-core/src/test/java/acceptance/task/GetTaskWithSorAccTest.java create mode 100644 lib/taskana-core/src/test/java/acceptance/task/UpdateTaskWithSorAccTest.java diff --git a/common/taskana-common-data/src/main/resources/sql/sample-data/object-reference.sql b/common/taskana-common-data/src/main/resources/sql/sample-data/object-reference.sql index eb6cdcd8b..14fa46fc4 100644 --- a/common/taskana-common-data/src/main/resources/sql/sample-data/object-reference.sql +++ b/common/taskana-common-data/src/main/resources/sql/sample-data/object-reference.sql @@ -1,3 +1,4 @@ -INSERT INTO OBJECT_REFERENCE VALUES ('1', 'Company1', 'System1', 'Instance1', 'Type1', 'Value1'); -INSERT INTO OBJECT_REFERENCE VALUES ('2', 'Company2', 'System2', 'Instance2', 'Type2', 'Value2'); -INSERT INTO OBJECT_REFERENCE VALUES ('3', 'Company3', 'System3', 'Instance3', 'Type3', 'Value3'); +INSERT INTO OBJECT_REFERENCE VALUES ('ID1', 'TKI:000000000000000000000000000000000000', 'Company1', 'System1', 'Instance1', 'Type1', 'Value1'); +INSERT INTO OBJECT_REFERENCE VALUES ('ID2', 'TKI:000000000000000000000000000000000000', 'Company2', 'System2', 'Instance2', 'Type2', 'Value2'); +INSERT INTO OBJECT_REFERENCE VALUES ('ID3', 'TKI:000000000000000000000000000000000001', 'Company3', 'System3', 'Instance3', 'Type3', 'Value2'); +INSERT INTO OBJECT_REFERENCE VALUES ('ID4', 'TKI:000000000000000000000000000000000002', 'Company1', 'System4', 'Instance4', 'Type2', 'Value2'); \ No newline at end of file diff --git a/common/taskana-common-data/src/main/resources/sql/test-data/object-reference.sql b/common/taskana-common-data/src/main/resources/sql/test-data/object-reference.sql index eb6cdcd8b..58084684b 100644 --- a/common/taskana-common-data/src/main/resources/sql/test-data/object-reference.sql +++ b/common/taskana-common-data/src/main/resources/sql/test-data/object-reference.sql @@ -1,3 +1,3 @@ -INSERT INTO OBJECT_REFERENCE VALUES ('1', 'Company1', 'System1', 'Instance1', 'Type1', 'Value1'); -INSERT INTO OBJECT_REFERENCE VALUES ('2', 'Company2', 'System2', 'Instance2', 'Type2', 'Value2'); -INSERT INTO OBJECT_REFERENCE VALUES ('3', 'Company3', 'System3', 'Instance3', 'Type3', 'Value3'); +INSERT INTO OBJECT_REFERENCE VALUES ('1', 'TaskId1', 'Company1', 'System1', 'Instance1', 'Type1', 'Value1'); +INSERT INTO OBJECT_REFERENCE VALUES ('2', 'TaskId2', 'Company2', 'System2', 'Instance2', 'Type2', 'Value2'); +INSERT INTO OBJECT_REFERENCE VALUES ('3', 'TaskId3', 'Company3', 'System3', 'Instance3', 'Type3', 'Value3'); diff --git a/common/taskana-common/src/main/java/pro/taskana/common/internal/util/IdGenerator.java b/common/taskana-common/src/main/java/pro/taskana/common/internal/util/IdGenerator.java index c698cd2e8..02bdf73cd 100644 --- a/common/taskana-common/src/main/java/pro/taskana/common/internal/util/IdGenerator.java +++ b/common/taskana-common/src/main/java/pro/taskana/common/internal/util/IdGenerator.java @@ -14,6 +14,7 @@ public final class IdGenerator { public static final String ID_PREFIX_EXT_TASK = "ETI"; public static final String ID_PREFIX_BUSINESS_PROCESS = "BPI"; public static final String ID_PREFIX_ATTACHMENT = "TAI"; + public static final String ID_PREFIX_OBJECT_REFERENCE = "ORI"; public static final String ID_PREFIX_TASK_COMMENT = "TCI"; diff --git a/common/taskana-common/src/main/resources/sql/db2/taskana-schema-db2.sql b/common/taskana-common/src/main/resources/sql/db2/taskana-schema-db2.sql index ab964122d..9a0a19c76 100644 --- a/common/taskana-common/src/main/resources/sql/db2/taskana-schema-db2.sql +++ b/common/taskana-common/src/main/resources/sql/db2/taskana-schema-db2.sql @@ -1,250 +1,265 @@ SET SCHEMA %schemaName%; -CREATE TABLE TASKANA_SCHEMA_VERSION( - ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), - VERSION VARCHAR(255) NOT NULL, - CREATED TIMESTAMP NOT NULL, - PRIMARY KEY (ID) +CREATE TABLE TASKANA_SCHEMA_VERSION +( + ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), + VERSION VARCHAR(255) NOT NULL, + CREATED TIMESTAMP NOT NULL, + PRIMARY KEY (ID) ); -- The VERSION value must match the value of TaskanaEngineConfiguration.TASKANA_SCHEMA_VERSION -INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) VALUES ('5.0.0', CURRENT_TIMESTAMP); +INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) +VALUES ('5.0.0', CURRENT_TIMESTAMP); -CREATE TABLE CLASSIFICATION( - ID VARCHAR(40) NOT NULL, - KEY VARCHAR(32) NOT NULL, - PARENT_ID VARCHAR(40) NOT NULL, - PARENT_KEY VARCHAR(32) NOT NULL, - CATEGORY VARCHAR(32), - TYPE VARCHAR(32), - DOMAIN VARCHAR(32) NOT NULL, - VALID_IN_DOMAIN SMALLINT NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - NAME VARCHAR(255) NULL, - DESCRIPTION VARCHAR(255) NULL, - PRIORITY INT NOT NULL, - SERVICE_LEVEL VARCHAR(255) NULL, +CREATE TABLE CLASSIFICATION +( + ID VARCHAR(40) NOT NULL, + KEY VARCHAR(32) NOT NULL, + PARENT_ID VARCHAR(40) NOT NULL, + PARENT_KEY VARCHAR(32) NOT NULL, + CATEGORY VARCHAR(32), + TYPE VARCHAR(32), + DOMAIN VARCHAR(32) NOT NULL, + VALID_IN_DOMAIN SMALLINT NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + NAME VARCHAR(255) NULL, + DESCRIPTION VARCHAR(255) NULL, + PRIORITY INT NOT NULL, + SERVICE_LEVEL VARCHAR(255) NULL, APPLICATION_ENTRY_POINT VARCHAR(255) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, PRIMARY KEY (ID), CONSTRAINT UC_CLASS_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); -CREATE TABLE WORKBASKET( - ID VARCHAR(40) NOT NULL, - KEY VARCHAR(64) NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - NAME VARCHAR(255) NOT NULL, - DOMAIN VARCHAR(32) NOT NULL, - TYPE VARCHAR(16) NOT NULL, - DESCRIPTION VARCHAR(255) NULL, - OWNER VARCHAR(128) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - ORG_LEVEL_1 VARCHAR(255) NULL, - ORG_LEVEL_2 VARCHAR(255) NULL, - ORG_LEVEL_3 VARCHAR(255) NULL, - ORG_LEVEL_4 VARCHAR(255) NULL, - MARKED_FOR_DELETION SMALLINT NOT NULL, +CREATE TABLE WORKBASKET +( + ID VARCHAR(40) NOT NULL, + KEY VARCHAR(64) NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + NAME VARCHAR(255) NOT NULL, + DOMAIN VARCHAR(32) NOT NULL, + TYPE VARCHAR(16) NOT NULL, + DESCRIPTION VARCHAR(255) NULL, + OWNER VARCHAR(128) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + ORG_LEVEL_1 VARCHAR(255) NULL, + ORG_LEVEL_2 VARCHAR(255) NULL, + ORG_LEVEL_3 VARCHAR(255) NULL, + ORG_LEVEL_4 VARCHAR(255) NULL, + MARKED_FOR_DELETION SMALLINT NOT NULL, PRIMARY KEY (ID), CONSTRAINT WB_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); -CREATE TABLE TASK ( - ID VARCHAR(40) NOT NULL, - EXTERNAL_ID VARCHAR(64) NOT NULL, - CREATED TIMESTAMP NULL, - CLAIMED TIMESTAMP NULL, - COMPLETED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - RECEIVED TIMESTAMP NULL, - PLANNED TIMESTAMP NULL, - DUE TIMESTAMP NULL, - NAME VARCHAR(255) NULL, - CREATOR VARCHAR(32) NULL, - DESCRIPTION VARCHAR(1024) NULL, - NOTE VARCHAR(4096) NULL, - PRIORITY INT NULL, - MANUAL_PRIORITY INT NULL, - STATE VARCHAR(20) NULL, - CLASSIFICATION_CATEGORY VARCHAR(32) NULL, - CLASSIFICATION_KEY VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - WORKBASKET_ID VARCHAR(40) NULL, - WORKBASKET_KEY VARCHAR(64) NULL, - DOMAIN VARCHAR(32) NULL, - BUSINESS_PROCESS_ID VARCHAR(128) NULL, - PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, - OWNER VARCHAR(32) NULL, - POR_COMPANY VARCHAR(32) NOT NULL, - POR_SYSTEM VARCHAR(32), - POR_INSTANCE VARCHAR(32), - POR_TYPE VARCHAR(32) NOT NULL, - POR_VALUE VARCHAR(128) NOT NULL, - IS_READ SMALLINT NOT NULL, - IS_TRANSFERRED SMALLINT NOT NULL, - CALLBACK_INFO CLOB NULL, - CALLBACK_STATE VARCHAR(30) NULL, - CUSTOM_ATTRIBUTES CLOB NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, - CUSTOM_9 VARCHAR(255) NULL, - CUSTOM_10 VARCHAR(255) NULL, - CUSTOM_11 VARCHAR(255) NULL, - CUSTOM_12 VARCHAR(255) NULL, - CUSTOM_13 VARCHAR(255) NULL, - CUSTOM_14 VARCHAR(255) NULL, - CUSTOM_15 VARCHAR(255) NULL, - CUSTOM_16 VARCHAR(255) NULL, - CUSTOM_INT_1 INT NULL, - CUSTOM_INT_2 INT NULL, - CUSTOM_INT_3 INT NULL, - CUSTOM_INT_4 INT NULL, - CUSTOM_INT_5 INT NULL, - CUSTOM_INT_6 INT NULL, - CUSTOM_INT_7 INT NULL, - CUSTOM_INT_8 INT NULL, - PRIMARY KEY (ID), - CONSTRAINT UC_EXTERNAL_ID UNIQUE (EXTERNAL_ID), - CONSTRAINT TASK_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE NO ACTION, - CONSTRAINT TASK_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION +CREATE TABLE TASK +( + ID VARCHAR(40) NOT NULL, + EXTERNAL_ID VARCHAR(64) NOT NULL, + CREATED TIMESTAMP NULL, + CLAIMED TIMESTAMP NULL, + COMPLETED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + RECEIVED TIMESTAMP NULL, + PLANNED TIMESTAMP NULL, + DUE TIMESTAMP NULL, + NAME VARCHAR(255) NULL, + CREATOR VARCHAR(32) NULL, + DESCRIPTION VARCHAR(1024) NULL, + NOTE VARCHAR(4096) NULL, + PRIORITY INT NULL, + MANUAL_PRIORITY INT NULL, + STATE VARCHAR(20) NULL, + CLASSIFICATION_CATEGORY VARCHAR(32) NULL, + CLASSIFICATION_KEY VARCHAR(32) NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + WORKBASKET_ID VARCHAR(40) NULL, + WORKBASKET_KEY VARCHAR(64) NULL, + DOMAIN VARCHAR(32) NULL, + BUSINESS_PROCESS_ID VARCHAR(128) NULL, + PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, + OWNER VARCHAR(32) NULL, + POR_COMPANY VARCHAR(32) NOT NULL, + POR_SYSTEM VARCHAR(32), + POR_INSTANCE VARCHAR(32), + POR_TYPE VARCHAR(32) NOT NULL, + POR_VALUE VARCHAR(128) NOT NULL, + IS_READ SMALLINT NOT NULL, + IS_TRANSFERRED SMALLINT NOT NULL, + CALLBACK_INFO CLOB NULL, + CALLBACK_STATE VARCHAR(30) NULL, + CUSTOM_ATTRIBUTES CLOB NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, + CUSTOM_9 VARCHAR(255) NULL, + CUSTOM_10 VARCHAR(255) NULL, + CUSTOM_11 VARCHAR(255) NULL, + CUSTOM_12 VARCHAR(255) NULL, + CUSTOM_13 VARCHAR(255) NULL, + CUSTOM_14 VARCHAR(255) NULL, + CUSTOM_15 VARCHAR(255) NULL, + CUSTOM_16 VARCHAR(255) NULL, + CUSTOM_INT_1 INT NULL, + CUSTOM_INT_2 INT NULL, + CUSTOM_INT_3 INT NULL, + CUSTOM_INT_4 INT NULL, + CUSTOM_INT_5 INT NULL, + CUSTOM_INT_6 INT NULL, + CUSTOM_INT_7 INT NULL, + CUSTOM_INT_8 INT NULL, + PRIMARY KEY (ID), + CONSTRAINT UC_EXTERNAL_ID UNIQUE (EXTERNAL_ID), + CONSTRAINT TASK_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE NO ACTION, + CONSTRAINT TASK_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION ); -CREATE TABLE DISTRIBUTION_TARGETS( - SOURCE_ID VARCHAR(40) NOT NULL, - TARGET_ID VARCHAR(40) NOT NULL, - PRIMARY KEY (SOURCE_ID, TARGET_ID) +CREATE TABLE DISTRIBUTION_TARGETS +( + SOURCE_ID VARCHAR(40) NOT NULL, + TARGET_ID VARCHAR(40) NOT NULL, + PRIMARY KEY (SOURCE_ID, TARGET_ID) ); -CREATE TABLE WORKBASKET_ACCESS_LIST( - ID VARCHAR(40) NOT NULL, - WORKBASKET_ID VARCHAR(40) NOT NULL, - ACCESS_ID VARCHAR(255) NOT NULL, - ACCESS_NAME VARCHAR(255) NULL, - PERM_READ SMALLINT NOT NULL, - PERM_OPEN SMALLINT NOT NULL, - PERM_APPEND SMALLINT NOT NULL, - PERM_TRANSFER SMALLINT NOT NULL, - PERM_DISTRIBUTE SMALLINT NOT NULL, - PERM_CUSTOM_1 SMALLINT NOT NULL, - PERM_CUSTOM_2 SMALLINT NOT NULL, - PERM_CUSTOM_3 SMALLINT NOT NULL, - PERM_CUSTOM_4 SMALLINT NOT NULL, - PERM_CUSTOM_5 SMALLINT NOT NULL, - PERM_CUSTOM_6 SMALLINT NOT NULL, - PERM_CUSTOM_7 SMALLINT NOT NULL, - PERM_CUSTOM_8 SMALLINT NOT NULL, - PERM_CUSTOM_9 SMALLINT NOT NULL, - PERM_CUSTOM_10 SMALLINT NOT NULL, - PERM_CUSTOM_11 SMALLINT NOT NULL, - PERM_CUSTOM_12 SMALLINT NOT NULL, - PRIMARY KEY (ID), - CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), - CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE +CREATE TABLE WORKBASKET_ACCESS_LIST +( + ID VARCHAR(40) NOT NULL, + WORKBASKET_ID VARCHAR(40) NOT NULL, + ACCESS_ID VARCHAR(255) NOT NULL, + ACCESS_NAME VARCHAR(255) NULL, + PERM_READ SMALLINT NOT NULL, + PERM_OPEN SMALLINT NOT NULL, + PERM_APPEND SMALLINT NOT NULL, + PERM_TRANSFER SMALLINT NOT NULL, + PERM_DISTRIBUTE SMALLINT NOT NULL, + PERM_CUSTOM_1 SMALLINT NOT NULL, + PERM_CUSTOM_2 SMALLINT NOT NULL, + PERM_CUSTOM_3 SMALLINT NOT NULL, + PERM_CUSTOM_4 SMALLINT NOT NULL, + PERM_CUSTOM_5 SMALLINT NOT NULL, + PERM_CUSTOM_6 SMALLINT NOT NULL, + PERM_CUSTOM_7 SMALLINT NOT NULL, + PERM_CUSTOM_8 SMALLINT NOT NULL, + PERM_CUSTOM_9 SMALLINT NOT NULL, + PERM_CUSTOM_10 SMALLINT NOT NULL, + PERM_CUSTOM_11 SMALLINT NOT NULL, + PERM_CUSTOM_12 SMALLINT NOT NULL, + PRIMARY KEY (ID), + CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), + CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE ); -CREATE TABLE OBJECT_REFERENCE( - ID VARCHAR(40) NOT NULL, - COMPANY VARCHAR(32) NOT NULL, - SYSTEM VARCHAR(32), - SYSTEM_INSTANCE VARCHAR(32), - TYPE VARCHAR(32) NOT NULL, - VALUE VARCHAR(128) NOT NULL +CREATE TABLE OBJECT_REFERENCE +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, + COMPANY VARCHAR(32) NOT NULL, + SYSTEM VARCHAR(32), + SYSTEM_INSTANCE VARCHAR(32), + TYPE VARCHAR(32) NOT NULL, + VALUE VARCHAR(128) NOT NULL ); -CREATE TABLE ATTACHMENT( - ID VARCHAR(40) NOT NULL, - TASK_ID VARCHAR(40) NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, +CREATE TABLE ATTACHMENT +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, CLASSIFICATION_KEY VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - REF_COMPANY VARCHAR(32) NOT NULL, - REF_SYSTEM VARCHAR(32), - REF_INSTANCE VARCHAR(32), - REF_TYPE VARCHAR(32) NOT NULL, - REF_VALUE VARCHAR(128) NOT NULL, - CHANNEL VARCHAR(64) NULL, - RECEIVED TIMESTAMP NULL, - CUSTOM_ATTRIBUTES CLOB NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + REF_COMPANY VARCHAR(32) NOT NULL, + REF_SYSTEM VARCHAR(32), + REF_INSTANCE VARCHAR(32), + REF_TYPE VARCHAR(32) NOT NULL, + REF_VALUE VARCHAR(128) NOT NULL, + CHANNEL VARCHAR(64) NULL, + RECEIVED TIMESTAMP NULL, + CUSTOM_ATTRIBUTES CLOB NULL, PRIMARY KEY (ID), CONSTRAINT ATT_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION ); -CREATE TABLE CONFIGURATION ( - NAME VARCHAR(8) NOT NULL, - ENFORCE_SECURITY BOOLEAN NULL, +CREATE TABLE CONFIGURATION +( + NAME VARCHAR(8) NOT NULL, + ENFORCE_SECURITY BOOLEAN NULL, CUSTOM_ATTRIBUTES CLOB NULL, PRIMARY KEY (NAME) ); -INSERT INTO CONFIGURATION (NAME) VALUES ('MASTER'); +INSERT INTO CONFIGURATION (NAME) +VALUES ('MASTER'); -CREATE TABLE TASK_COMMENT( - ID VARCHAR(40) NOT NULL, - TASK_ID VARCHAR(40) NOT NULL, +CREATE TABLE TASK_COMMENT +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, TEXT_FIELD VARCHAR(1024) NULL, - CREATOR VARCHAR(32) NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, + CREATOR VARCHAR(32) NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, PRIMARY KEY (ID), CONSTRAINT COMMENT_TASK FOREIGN KEY (TASK_ID) REFERENCES TASK ON DELETE CASCADE ); -CREATE TABLE SCHEDULED_JOB( - JOB_ID INTEGER NOT NULL, - PRIORITY INTEGER NULL, - CREATED TIMESTAMP NULL, - DUE TIMESTAMP NULL, - STATE VARCHAR(32) NULL, - LOCKED_BY VARCHAR(32) NULL, - LOCK_EXPIRES TIMESTAMP NULL, - TYPE VARCHAR(255) NULL, - RETRY_COUNT INTEGER NOT NULL, - ARGUMENTS CLOB NULL, - PRIMARY KEY (JOB_ID) +CREATE TABLE SCHEDULED_JOB +( + JOB_ID INTEGER NOT NULL, + PRIORITY INTEGER NULL, + CREATED TIMESTAMP NULL, + DUE TIMESTAMP NULL, + STATE VARCHAR(32) NULL, + LOCKED_BY VARCHAR(32) NULL, + LOCK_EXPIRES TIMESTAMP NULL, + TYPE VARCHAR(255) NULL, + RETRY_COUNT INTEGER NOT NULL, + ARGUMENTS CLOB NULL, + PRIMARY KEY (JOB_ID) ); -CREATE TABLE TASK_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, +CREATE TABLE TASK_HISTORY_EVENT +( + ID VARCHAR(40) NOT NULL, BUSINESS_PROCESS_ID VARCHAR(128) NULL, PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, - TASK_ID VARCHAR(40) NULL, - EVENT_TYPE VARCHAR(32) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - DOMAIN VARCHAR(32) NULL, - WORKBASKET_KEY VARCHAR(64) NULL, + TASK_ID VARCHAR(40) NULL, + EVENT_TYPE VARCHAR(32) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + DOMAIN VARCHAR(32) NULL, + WORKBASKET_KEY VARCHAR(64) NULL, WORKBASKET_NAME VARCHAR(255) NULL, - POR_COMPANY VARCHAR(32) NULL, - POR_SYSTEM VARCHAR(32) NULL, - POR_INSTANCE VARCHAR(32) NULL, - POR_TYPE VARCHAR(32) NULL, + POR_COMPANY VARCHAR(32) NULL, + POR_SYSTEM VARCHAR(32) NULL, + POR_INSTANCE VARCHAR(32) NULL, + POR_TYPE VARCHAR(32) NULL, POR_VALUE VARCHAR(128) NULL, - TASK_PRIORITY INT NULL, - TASK_PLANNED TIMESTAMP NULL, - TASK_DUE TIMESTAMP NULL, - TASK_OWNER VARCHAR(32) NULL, - TASK_CLASSIFICATION_KEY VARCHAR(32) NULL, - TASK_CLASSIFICATION_NAME VARCHAR(32) NULL, - TASK_CLASSIFICATION_CATEGORY VARCHAR(32) NULL, - ATTACHMENT_CLASSIFICATION_KEY VARCHAR(32) NULL, + TASK_PRIORITY INT NULL, + TASK_PLANNED TIMESTAMP NULL, + TASK_DUE TIMESTAMP NULL, + TASK_OWNER VARCHAR(32) NULL, + TASK_CLASSIFICATION_KEY VARCHAR(32) NULL, + TASK_CLASSIFICATION_NAME VARCHAR(32) NULL, + TASK_CLASSIFICATION_CATEGORY VARCHAR(32) NULL, + ATTACHMENT_CLASSIFICATION_KEY VARCHAR(32) NULL, ATTACHMENT_CLASSIFICATION_NAME VARCHAR(255) NULL, OLD_VALUE VARCHAR(255) NULL, NEW_VALUE VARCHAR(255) NULL, @@ -252,86 +267,86 @@ CREATE TABLE TASK_HISTORY_EVENT ( CUSTOM_2 VARCHAR(128) NULL, CUSTOM_3 VARCHAR(128) NULL, CUSTOM_4 VARCHAR(128) NULL, - DETAILS CLOB NULL, + DETAILS CLOB NULL, PRIMARY KEY (ID) ); CREATE TABLE WORKBASKET_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, - EVENT_TYPE VARCHAR(40) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - DOMAIN VARCHAR(32) NULL, - WORKBASKET_ID VARCHAR(40) NULL, - KEY VARCHAR(64) NULL, - TYPE VARCHAR(64) NULL, - OWNER VARCHAR(128) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - ORGLEVEL_1 VARCHAR(255) NULL, - ORGLEVEL_2 VARCHAR(255) NULL, - ORGLEVEL_3 VARCHAR(255) NULL, - ORGLEVEL_4 VARCHAR(255) NULL, - DETAILS CLOB NULL, + ID VARCHAR(40) NOT NULL, + EVENT_TYPE VARCHAR(40) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + DOMAIN VARCHAR(32) NULL, + WORKBASKET_ID VARCHAR(40) NULL, + KEY VARCHAR(64) NULL, + TYPE VARCHAR(64) NULL, + OWNER VARCHAR(128) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + ORGLEVEL_1 VARCHAR(255) NULL, + ORGLEVEL_2 VARCHAR(255) NULL, + ORGLEVEL_3 VARCHAR(255) NULL, + ORGLEVEL_4 VARCHAR(255) NULL, + DETAILS CLOB NULL, PRIMARY KEY (ID) ); CREATE TABLE CLASSIFICATION_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, - EVENT_TYPE VARCHAR(40) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - APPLICATION_ENTRY_POINT VARCHAR(255) NULL, - CATEGORY VARCHAR(64) NULL, - DOMAIN VARCHAR(32) NULL, - KEY VARCHAR(40) NULL, - NAME VARCHAR(255) NULL, - PARENT_ID VARCHAR(40) NOT NULL, - PARENT_KEY VARCHAR(32) NOT NULL, - PRIORITY INT NOT NULL, - SERVICE_LEVEL VARCHAR(255) NULL, - TYPE VARCHAR(32), - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, - DETAILS CLOB NULL, + ID VARCHAR(40) NOT NULL, + EVENT_TYPE VARCHAR(40) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + APPLICATION_ENTRY_POINT VARCHAR(255) NULL, + CATEGORY VARCHAR(64) NULL, + DOMAIN VARCHAR(32) NULL, + KEY VARCHAR(40) NULL, + NAME VARCHAR(255) NULL, + PARENT_ID VARCHAR(40) NOT NULL, + PARENT_KEY VARCHAR(32) NOT NULL, + PRIORITY INT NOT NULL, + SERVICE_LEVEL VARCHAR(255) NULL, + TYPE VARCHAR(32), + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, + DETAILS CLOB NULL, PRIMARY KEY (ID) ); -- USER can not be taken as table name because it is a reserved keyword. -CREATE TABLE USER_INFO ( - USER_ID VARCHAR(32) NOT NULL, - FIRST_NAME VARCHAR(32) NULL, - LASTNAME VARCHAR(32) NULL, - FULL_NAME VARCHAR(64) NULL, - LONG_NAME VARCHAR(64) NULL, - E_MAIL VARCHAR(64) NULL, - PHONE VARCHAR(32) NULL, - MOBILE_PHONE VARCHAR(32) NULL, - ORG_LEVEL_4 VARCHAR(32) NULL, - ORG_LEVEL_3 VARCHAR(32) NULL, - ORG_LEVEL_2 VARCHAR(32) NULL, - ORG_LEVEL_1 VARCHAR(32) NULL, - DATA CLOB NULL, +CREATE TABLE USER_INFO +( + USER_ID VARCHAR(32) NOT NULL, + FIRST_NAME VARCHAR(32) NULL, + LASTNAME VARCHAR(32) NULL, + FULL_NAME VARCHAR(64) NULL, + LONG_NAME VARCHAR(64) NULL, + E_MAIL VARCHAR(64) NULL, + PHONE VARCHAR(32) NULL, + MOBILE_PHONE VARCHAR(32) NULL, + ORG_LEVEL_4 VARCHAR(32) NULL, + ORG_LEVEL_3 VARCHAR(32) NULL, + ORG_LEVEL_2 VARCHAR(32) NULL, + ORG_LEVEL_1 VARCHAR(32) NULL, + DATA CLOB NULL, PRIMARY KEY (USER_ID) ); CREATE SEQUENCE SCHEDULED_JOB_SEQ - MINVALUE 1 - START WITH 1 - INCREMENT BY 1 - CACHE 10; + MINVALUE 1 + START WITH 1 + INCREMENT BY 1 CACHE 10; -- LIST OF RECOMMENDED INDEXES @@ -339,76 +354,67 @@ CREATE SEQUENCE SCHEDULED_JOB_SEQ -- The script needs to be reviewed and adapted for each indiviual TASKANA setup. -- =========================== CREATE UNIQUE INDEX IDX_CLASSIFICATION_ID ON CLASSIFICATION - ("ID" ASC) - INCLUDE ("CUSTOM_8", "CUSTOM_7", "CUSTOM_6", "CUSTOM_5", "CUSTOM_4", "CUSTOM_3", "CUSTOM_2", + ("ID" ASC) INCLUDE ("CUSTOM_8", "CUSTOM_7", "CUSTOM_6", "CUSTOM_5", "CUSTOM_4", "CUSTOM_3", "CUSTOM_2", "CUSTOM_1", "APPLICATION_ENTRY_POINT", "SERVICE_LEVEL", "PRIORITY", "DESCRIPTION", "NAME", "CREATED", "VALID_IN_DOMAIN", "DOMAIN", "TYPE", "CATEGORY", "PARENT_KEY", "PARENT_ID", "KEY") ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; +COMMIT WORK; CREATE INDEX IDX_CLASSIFICATION_CATEGORY ON CLASSIFICATION - ("CATEGORY" ASC, "DOMAIN" ASC, "TYPE" ASC, "CUSTOM_1" ASC, "CUSTOM_8" ASC, "CUSTOM_7" ASC, - "CUSTOM_6" ASC, "CUSTOM_5" ASC, "CUSTOM_4" ASC, "CUSTOM_3" ASC, "CUSTOM_2" ASC, - "APPLICATION_ENTRY_POINT" ASC, "SERVICE_LEVEL" ASC, "PRIORITY" ASC, "DESCRIPTION" ASC, - "NAME" ASC, "CREATED" ASC, "VALID_IN_DOMAIN" ASC, "PARENT_KEY" ASC, "PARENT_ID" ASC, "KEY" ASC, - "ID" ASC) - ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; + ("CATEGORY" ASC, "DOMAIN" ASC, "TYPE" ASC, "CUSTOM_1" ASC, "CUSTOM_8" ASC, "CUSTOM_7" ASC, + "CUSTOM_6" ASC, "CUSTOM_5" ASC, "CUSTOM_4" ASC, "CUSTOM_3" ASC, "CUSTOM_2" ASC, + "APPLICATION_ENTRY_POINT" ASC, "SERVICE_LEVEL" ASC, "PRIORITY" ASC, "DESCRIPTION" ASC, + "NAME" ASC, "CREATED" ASC, "VALID_IN_DOMAIN" ASC, "PARENT_KEY" ASC, "PARENT_ID" ASC, "KEY" ASC, + "ID" ASC) ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; +COMMIT WORK; CREATE UNIQUE INDEX IDX_CLASSIFICATION_KEY_DOMAIN ON CLASSIFICATION - ("KEY" ASC, "DOMAIN" ASC) - INCLUDE ("CUSTOM_8", "CUSTOM_7", "CUSTOM_6", "CUSTOM_5", "CUSTOM_4", "CUSTOM_3", "CUSTOM_2", + ("KEY" ASC, "DOMAIN" ASC) INCLUDE ("CUSTOM_8", "CUSTOM_7", "CUSTOM_6", "CUSTOM_5", "CUSTOM_4", "CUSTOM_3", "CUSTOM_2", "CUSTOM_1", "APPLICATION_ENTRY_POINT", "SERVICE_LEVEL", "PRIORITY", "DESCRIPTION", "NAME", "CREATED", "VALID_IN_DOMAIN", "TYPE", "CATEGORY", "PARENT_KEY", "PARENT_ID", "ID") ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; +COMMIT WORK; CREATE INDEX IDX_TASK_WORKBASKET_KEY_DOMAIN ON TASK - ("WORKBASKET_KEY" ASC, "DOMAIN" DESC) - ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; + ("WORKBASKET_KEY" ASC, "DOMAIN" DESC) ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; +COMMIT WORK; CREATE INDEX IDX_TASK_POR_VALUE ON TASK - (UPPER("POR_VALUE") ASC, "WORKBASKET_ID" ASC) - ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; + (UPPER("POR_VALUE") ASC, "WORKBASKET_ID" ASC) ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; +COMMIT WORK; CREATE INDEX IDX_ATTACHMENT_TASK_ID ON ATTACHMENT - ("TASK_ID" ASC, "RECEIVED" ASC, "CLASSIFICATION_ID" ASC, "CLASSIFICATION_KEY" ASC, - "MODIFIED" ASC, "CREATED" ASC, "ID" ASC) - ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; + ("TASK_ID" ASC, "RECEIVED" ASC, "CLASSIFICATION_ID" ASC, "CLASSIFICATION_KEY" ASC, + "MODIFIED" ASC, "CREATED" ASC, "ID" + ASC) ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; +COMMIT WORK; CREATE UNIQUE INDEX IDX_WORKBASKET_ID ON WORKBASKET - ("ID" ASC) - INCLUDE ("ORG_LEVEL_4", "ORG_LEVEL_3", "ORG_LEVEL_2", "ORG_LEVEL_1", "OWNER", "DESCRIPTION", + ("ID" ASC) INCLUDE ("ORG_LEVEL_4", "ORG_LEVEL_3", "ORG_LEVEL_2", "ORG_LEVEL_1", "OWNER", "DESCRIPTION", "TYPE", "DOMAIN", "NAME", "KEY") ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; +COMMIT WORK; CREATE UNIQUE INDEX IDX_WORKBASKET_KEY_DOMAIN ON WORKBASKET - ("KEY" ASC, "DOMAIN" ASC) - INCLUDE ("ORG_LEVEL_4", "ORG_LEVEL_3", "ORG_LEVEL_2", "ORG_LEVEL_1", "CUSTOM_4", "CUSTOM_3", + ("KEY" ASC, "DOMAIN" ASC) INCLUDE ("ORG_LEVEL_4", "ORG_LEVEL_3", "ORG_LEVEL_2", "ORG_LEVEL_1", "CUSTOM_4", "CUSTOM_3", "CUSTOM_2", "CUSTOM_1", "OWNER", "DESCRIPTION", "TYPE", "NAME", "MODIFIED", "CREATED", "ID") ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; +COMMIT WORK; CREATE UNIQUE INDEX IDX_WORKBASKET_KEY_DOMAIN_ID ON WORKBASKET - ("KEY" ASC, "DOMAIN" ASC) - INCLUDE ("ID") + ("KEY" ASC, "DOMAIN" ASC) INCLUDE ("ID") ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; +COMMIT WORK; CREATE INDEX IDX_WORKBASKET_ACCESS_LIST_ACCESS_ID ON WORKBASKET_ACCESS_LIST - ("ACCESS_ID" ASC, "WORKBASKET_ID" ASC, "PERM_READ" ASC) - ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; -COMMIT WORK ; + ("ACCESS_ID" ASC, "WORKBASKET_ID" ASC, "PERM_READ" ASC) ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; +COMMIT WORK; CREATE INDEX IDX_WORKBASKET_ACCESS_LIST_WORKBASKET_ID ON WORKBASKET_ACCESS_LIST - ("WORKBASKET_ID" ASC, "PERM_CUSTOM_12" ASC, "PERM_CUSTOM_11" ASC, "PERM_CUSTOM_10" ASC, - "PERM_CUSTOM_9" ASC, "PERM_CUSTOM_8" ASC, "PERM_CUSTOM_7" ASC, "PERM_CUSTOM_6" ASC, - "PERM_CUSTOM_5" ASC, "PERM_CUSTOM_4" ASC, "PERM_CUSTOM_3" ASC, "PERM_CUSTOM_2" ASC, - "PERM_CUSTOM_1" ASC, "PERM_DISTRIBUTE" ASC, "PERM_TRANSFER" ASC, "PERM_APPEND" ASC, - "PERM_OPEN" ASC, "PERM_READ" ASC, "ACCESS_ID" ASC) - ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; - COMMIT WORK ; + ("WORKBASKET_ID" ASC, "PERM_CUSTOM_12" ASC, "PERM_CUSTOM_11" ASC, "PERM_CUSTOM_10" ASC, + "PERM_CUSTOM_9" ASC, "PERM_CUSTOM_8" ASC, "PERM_CUSTOM_7" ASC, "PERM_CUSTOM_6" ASC, + "PERM_CUSTOM_5" ASC, "PERM_CUSTOM_4" ASC, "PERM_CUSTOM_3" ASC, "PERM_CUSTOM_2" ASC, + "PERM_CUSTOM_1" ASC, "PERM_DISTRIBUTE" ASC, "PERM_TRANSFER" ASC, "PERM_APPEND" ASC, + "PERM_OPEN" ASC, "PERM_READ" ASC, "ACCESS_ID" + ASC) ALLOW REVERSE SCANS COLLECT SAMPLED DETAILED STATISTICS; +COMMIT WORK; \ No newline at end of file diff --git a/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_4.11.0_to_5.0.0_db2.sql b/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_4.11.0_to_5.0.0_db2.sql index 911aa8de2..8ac5c8898 100644 --- a/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_4.11.0_to_5.0.0_db2.sql +++ b/common/taskana-common/src/main/resources/sql/db2/taskana_schema_update_4.11.0_to_5.0.0_db2.sql @@ -4,6 +4,8 @@ SET SCHEMA %schemaName%; INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) VALUES ('5.0.0', CURRENT_TIMESTAMP); +ALTER TABLE OBJECT_REFERENCE ADD COLUMN TASK_ID VARCHAR(40) NOT NULL DEFAULT 'EMPTY'; + DROP INDEX "DB2ADMIN"."IDX1805212017540"; DROP INDEX "DB2ADMIN"."IDX1805212018000"; DROP INDEX "DB2ADMIN"."IDX1805212018030"; diff --git a/common/taskana-common/src/main/resources/sql/h2/taskana-schema-h2.sql b/common/taskana-common/src/main/resources/sql/h2/taskana-schema-h2.sql index 737abba3a..806019422 100644 --- a/common/taskana-common/src/main/resources/sql/h2/taskana-schema-h2.sql +++ b/common/taskana-common/src/main/resources/sql/h2/taskana-schema-h2.sql @@ -7,242 +7,255 @@ SET SCHEMA %schemaName%; -- here in this file! -- SET COLLATION DEFAULT_de_DE; -CREATE TABLE TASKANA_SCHEMA_VERSION( - ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), - VERSION VARCHAR(255) NOT NULL, - CREATED TIMESTAMP NOT NULL, - PRIMARY KEY (ID) +CREATE TABLE TASKANA_SCHEMA_VERSION +( + ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), + VERSION VARCHAR(255) NOT NULL, + CREATED TIMESTAMP NOT NULL, + PRIMARY KEY (ID) ); -- The VERSION value must match the value of TaskanaEngineConfiguration.TASKANA_SCHEMA_VERSION -INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) VALUES ('5.0.0', CURRENT_TIMESTAMP); +INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) +VALUES ('5.0.0', CURRENT_TIMESTAMP); -CREATE TABLE CLASSIFICATION( - ID VARCHAR(40) NOT NULL, - KEY VARCHAR(32) NOT NULL, - PARENT_ID VARCHAR(40) NOT NULL, - PARENT_KEY VARCHAR(32) NOT NULL, - CATEGORY VARCHAR(32), - TYPE VARCHAR(32), - DOMAIN VARCHAR(32) NOT NULL, - VALID_IN_DOMAIN SMALLINT NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - NAME VARCHAR(255) NULL, - DESCRIPTION VARCHAR(255) NULL, - PRIORITY INT NOT NULL, - SERVICE_LEVEL VARCHAR(255) NULL, +CREATE TABLE CLASSIFICATION +( + ID VARCHAR(40) NOT NULL, + KEY VARCHAR(32) NOT NULL, + PARENT_ID VARCHAR(40) NOT NULL, + PARENT_KEY VARCHAR(32) NOT NULL, + CATEGORY VARCHAR(32), + TYPE VARCHAR(32), + DOMAIN VARCHAR(32) NOT NULL, + VALID_IN_DOMAIN SMALLINT NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + NAME VARCHAR(255) NULL, + DESCRIPTION VARCHAR(255) NULL, + PRIORITY INT NOT NULL, + SERVICE_LEVEL VARCHAR(255) NULL, APPLICATION_ENTRY_POINT VARCHAR(255) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, PRIMARY KEY (ID), CONSTRAINT UC_CLASS_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); -CREATE TABLE WORKBASKET( - ID VARCHAR(40) NOT NULL, - KEY VARCHAR(64) NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - NAME VARCHAR(255) NOT NULL, - DOMAIN VARCHAR(32) NOT NULL, - TYPE VARCHAR(16) NOT NULL, - DESCRIPTION VARCHAR(255) NULL, - OWNER VARCHAR(128) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - ORG_LEVEL_1 VARCHAR(255) NULL, - ORG_LEVEL_2 VARCHAR(255) NULL, - ORG_LEVEL_3 VARCHAR(255) NULL, - ORG_LEVEL_4 VARCHAR(255) NULL, - MARKED_FOR_DELETION SMALLINT NOT NULL, +CREATE TABLE WORKBASKET +( + ID VARCHAR(40) NOT NULL, + KEY VARCHAR(64) NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + NAME VARCHAR(255) NOT NULL, + DOMAIN VARCHAR(32) NOT NULL, + TYPE VARCHAR(16) NOT NULL, + DESCRIPTION VARCHAR(255) NULL, + OWNER VARCHAR(128) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + ORG_LEVEL_1 VARCHAR(255) NULL, + ORG_LEVEL_2 VARCHAR(255) NULL, + ORG_LEVEL_3 VARCHAR(255) NULL, + ORG_LEVEL_4 VARCHAR(255) NULL, + MARKED_FOR_DELETION SMALLINT NOT NULL, PRIMARY KEY (ID), CONSTRAINT WB_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); -CREATE TABLE TASK ( - ID VARCHAR(40) NOT NULL, - EXTERNAL_ID VARCHAR(64) NOT NULL, - CREATED TIMESTAMP NULL, - CLAIMED TIMESTAMP NULL, - COMPLETED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - RECEIVED TIMESTAMP NULL, - PLANNED TIMESTAMP NULL, - DUE TIMESTAMP NULL, - NAME VARCHAR(255) NULL, - CREATOR VARCHAR(32) NULL, - DESCRIPTION VARCHAR(1024) NULL, - NOTE VARCHAR(4096) NULL, - PRIORITY INT NULL, - MANUAL_PRIORITY INT NULL, - STATE VARCHAR(20) NULL, - CLASSIFICATION_CATEGORY VARCHAR(32) NULL, - CLASSIFICATION_KEY VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - WORKBASKET_ID VARCHAR(40) NULL, - WORKBASKET_KEY VARCHAR(64) NULL, - DOMAIN VARCHAR(32) NULL, - BUSINESS_PROCESS_ID VARCHAR(128) NULL, - PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, - OWNER VARCHAR(32) NULL, - POR_COMPANY VARCHAR(32) NOT NULL, - POR_SYSTEM VARCHAR(32), - POR_INSTANCE VARCHAR(32), - POR_TYPE VARCHAR(32) NOT NULL, - POR_VALUE VARCHAR(128) NOT NULL, - IS_READ SMALLINT NOT NULL, - IS_TRANSFERRED SMALLINT NOT NULL, - CALLBACK_INFO CLOB NULL, - CALLBACK_STATE VARCHAR(30) NULL, - CUSTOM_ATTRIBUTES CLOB NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, - CUSTOM_9 VARCHAR(255) NULL, - CUSTOM_10 VARCHAR(255) NULL, - CUSTOM_11 VARCHAR(255) NULL, - CUSTOM_12 VARCHAR(255) NULL, - CUSTOM_13 VARCHAR(255) NULL, - CUSTOM_14 VARCHAR(255) NULL, - CUSTOM_15 VARCHAR(255) NULL, - CUSTOM_16 VARCHAR(255) NULL, - CUSTOM_INT_1 INT NULL, - CUSTOM_INT_2 INT NULL, - CUSTOM_INT_3 INT NULL, - CUSTOM_INT_4 INT NULL, - CUSTOM_INT_5 INT NULL, - CUSTOM_INT_6 INT NULL, - CUSTOM_INT_7 INT NULL, - CUSTOM_INT_8 INT NULL, - PRIMARY KEY (ID), - CONSTRAINT UC_EXTERNAL_ID UNIQUE (EXTERNAL_ID), - CONSTRAINT TASK_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE NO ACTION, - CONSTRAINT TASK_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION +CREATE TABLE TASK +( + ID VARCHAR(40) NOT NULL, + EXTERNAL_ID VARCHAR(64) NOT NULL, + CREATED TIMESTAMP NULL, + CLAIMED TIMESTAMP NULL, + COMPLETED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + RECEIVED TIMESTAMP NULL, + PLANNED TIMESTAMP NULL, + DUE TIMESTAMP NULL, + NAME VARCHAR(255) NULL, + CREATOR VARCHAR(32) NULL, + DESCRIPTION VARCHAR(1024) NULL, + NOTE VARCHAR(4096) NULL, + PRIORITY INT NULL, + MANUAL_PRIORITY INT NULL, + STATE VARCHAR(20) NULL, + CLASSIFICATION_CATEGORY VARCHAR(32) NULL, + CLASSIFICATION_KEY VARCHAR(32) NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + WORKBASKET_ID VARCHAR(40) NULL, + WORKBASKET_KEY VARCHAR(64) NULL, + DOMAIN VARCHAR(32) NULL, + BUSINESS_PROCESS_ID VARCHAR(128) NULL, + PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, + OWNER VARCHAR(32) NULL, + POR_COMPANY VARCHAR(32) NOT NULL, + POR_SYSTEM VARCHAR(32), + POR_INSTANCE VARCHAR(32), + POR_TYPE VARCHAR(32) NOT NULL, + POR_VALUE VARCHAR(128) NOT NULL, + IS_READ SMALLINT NOT NULL, + IS_TRANSFERRED SMALLINT NOT NULL, + CALLBACK_INFO CLOB NULL, + CALLBACK_STATE VARCHAR(30) NULL, + CUSTOM_ATTRIBUTES CLOB NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, + CUSTOM_9 VARCHAR(255) NULL, + CUSTOM_10 VARCHAR(255) NULL, + CUSTOM_11 VARCHAR(255) NULL, + CUSTOM_12 VARCHAR(255) NULL, + CUSTOM_13 VARCHAR(255) NULL, + CUSTOM_14 VARCHAR(255) NULL, + CUSTOM_15 VARCHAR(255) NULL, + CUSTOM_16 VARCHAR(255) NULL, + CUSTOM_INT_1 INT NULL, + CUSTOM_INT_2 INT NULL, + CUSTOM_INT_3 INT NULL, + CUSTOM_INT_4 INT NULL, + CUSTOM_INT_5 INT NULL, + CUSTOM_INT_6 INT NULL, + CUSTOM_INT_7 INT NULL, + CUSTOM_INT_8 INT NULL, + PRIMARY KEY (ID), + CONSTRAINT UC_EXTERNAL_ID UNIQUE (EXTERNAL_ID), + CONSTRAINT TASK_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE NO ACTION, + CONSTRAINT TASK_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION ); -CREATE TABLE DISTRIBUTION_TARGETS( - SOURCE_ID VARCHAR(40) NOT NULL, - TARGET_ID VARCHAR(40) NOT NULL, - PRIMARY KEY (SOURCE_ID, TARGET_ID) +CREATE TABLE DISTRIBUTION_TARGETS +( + SOURCE_ID VARCHAR(40) NOT NULL, + TARGET_ID VARCHAR(40) NOT NULL, + PRIMARY KEY (SOURCE_ID, TARGET_ID) ); -CREATE TABLE WORKBASKET_ACCESS_LIST( - ID VARCHAR(40) NOT NULL, - WORKBASKET_ID VARCHAR(40) NOT NULL, - ACCESS_ID VARCHAR(255) NOT NULL, - ACCESS_NAME VARCHAR(255) NULL, - PERM_READ SMALLINT NOT NULL, - PERM_OPEN SMALLINT NOT NULL, - PERM_APPEND SMALLINT NOT NULL, - PERM_TRANSFER SMALLINT NOT NULL, - PERM_DISTRIBUTE SMALLINT NOT NULL, - PERM_CUSTOM_1 SMALLINT NOT NULL, - PERM_CUSTOM_2 SMALLINT NOT NULL, - PERM_CUSTOM_3 SMALLINT NOT NULL, - PERM_CUSTOM_4 SMALLINT NOT NULL, - PERM_CUSTOM_5 SMALLINT NOT NULL, - PERM_CUSTOM_6 SMALLINT NOT NULL, - PERM_CUSTOM_7 SMALLINT NOT NULL, - PERM_CUSTOM_8 SMALLINT NOT NULL, - PERM_CUSTOM_9 SMALLINT NOT NULL, - PERM_CUSTOM_10 SMALLINT NOT NULL, - PERM_CUSTOM_11 SMALLINT NOT NULL, - PERM_CUSTOM_12 SMALLINT NOT NULL, - PRIMARY KEY (ID), - CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), - CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE +CREATE TABLE WORKBASKET_ACCESS_LIST +( + ID VARCHAR(40) NOT NULL, + WORKBASKET_ID VARCHAR(40) NOT NULL, + ACCESS_ID VARCHAR(255) NOT NULL, + ACCESS_NAME VARCHAR(255) NULL, + PERM_READ SMALLINT NOT NULL, + PERM_OPEN SMALLINT NOT NULL, + PERM_APPEND SMALLINT NOT NULL, + PERM_TRANSFER SMALLINT NOT NULL, + PERM_DISTRIBUTE SMALLINT NOT NULL, + PERM_CUSTOM_1 SMALLINT NOT NULL, + PERM_CUSTOM_2 SMALLINT NOT NULL, + PERM_CUSTOM_3 SMALLINT NOT NULL, + PERM_CUSTOM_4 SMALLINT NOT NULL, + PERM_CUSTOM_5 SMALLINT NOT NULL, + PERM_CUSTOM_6 SMALLINT NOT NULL, + PERM_CUSTOM_7 SMALLINT NOT NULL, + PERM_CUSTOM_8 SMALLINT NOT NULL, + PERM_CUSTOM_9 SMALLINT NOT NULL, + PERM_CUSTOM_10 SMALLINT NOT NULL, + PERM_CUSTOM_11 SMALLINT NOT NULL, + PERM_CUSTOM_12 SMALLINT NOT NULL, + PRIMARY KEY (ID), + CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), + CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE ); -CREATE TABLE OBJECT_REFERENCE( - ID VARCHAR(40) NOT NULL, - COMPANY VARCHAR(32) NOT NULL, - SYSTEM VARCHAR(32), - SYSTEM_INSTANCE VARCHAR(32), - TYPE VARCHAR(32) NOT NULL, - VALUE VARCHAR(128) NOT NULL +CREATE TABLE OBJECT_REFERENCE +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, + COMPANY VARCHAR(32) NOT NULL, + SYSTEM VARCHAR(32), + SYSTEM_INSTANCE VARCHAR(32), + TYPE VARCHAR(32) NOT NULL, + VALUE VARCHAR(128) NOT NULL ); -CREATE TABLE ATTACHMENT( - ID VARCHAR(40) NOT NULL, - TASK_ID VARCHAR(40) NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, +CREATE TABLE ATTACHMENT +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, CLASSIFICATION_KEY VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - REF_COMPANY VARCHAR(32) NOT NULL, - REF_SYSTEM VARCHAR(32), - REF_INSTANCE VARCHAR(32), - REF_TYPE VARCHAR(32) NOT NULL, - REF_VALUE VARCHAR(128) NOT NULL, - CHANNEL VARCHAR(64) NULL, - RECEIVED TIMESTAMP NULL, - CUSTOM_ATTRIBUTES CLOB NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + REF_COMPANY VARCHAR(32) NOT NULL, + REF_SYSTEM VARCHAR(32), + REF_INSTANCE VARCHAR(32), + REF_TYPE VARCHAR(32) NOT NULL, + REF_VALUE VARCHAR(128) NOT NULL, + CHANNEL VARCHAR(64) NULL, + RECEIVED TIMESTAMP NULL, + CUSTOM_ATTRIBUTES CLOB NULL, PRIMARY KEY (ID), CONSTRAINT ATT_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION ); -CREATE TABLE TASK_COMMENT( - ID VARCHAR(40) NOT NULL, - TASK_ID VARCHAR(40) NOT NULL, +CREATE TABLE TASK_COMMENT +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, TEXT_FIELD VARCHAR(1024) NULL, - CREATOR VARCHAR(32) NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, + CREATOR VARCHAR(32) NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, PRIMARY KEY (ID), CONSTRAINT COMMENT_TASK FOREIGN KEY (TASK_ID) REFERENCES TASK ON DELETE CASCADE ); -CREATE TABLE SCHEDULED_JOB( - JOB_ID INTEGER NOT NULL, - PRIORITY INTEGER NULL, - CREATED TIMESTAMP NULL, - DUE TIMESTAMP NULL, - STATE VARCHAR(32) NULL, - LOCKED_BY VARCHAR(32) NULL, - LOCK_EXPIRES TIMESTAMP NULL, - TYPE VARCHAR(255) NULL, - RETRY_COUNT INTEGER NOT NULL, - ARGUMENTS CLOB NULL, - PRIMARY KEY (JOB_ID) +CREATE TABLE SCHEDULED_JOB +( + JOB_ID INTEGER NOT NULL, + PRIORITY INTEGER NULL, + CREATED TIMESTAMP NULL, + DUE TIMESTAMP NULL, + STATE VARCHAR(32) NULL, + LOCKED_BY VARCHAR(32) NULL, + LOCK_EXPIRES TIMESTAMP NULL, + TYPE VARCHAR(255) NULL, + RETRY_COUNT INTEGER NOT NULL, + ARGUMENTS CLOB NULL, + PRIMARY KEY (JOB_ID) ); -CREATE TABLE TASK_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, +CREATE TABLE TASK_HISTORY_EVENT +( + ID VARCHAR(40) NOT NULL, BUSINESS_PROCESS_ID VARCHAR(128) NULL, PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, - TASK_ID VARCHAR(40) NULL, - EVENT_TYPE VARCHAR(32) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - DOMAIN VARCHAR(32) NULL, - WORKBASKET_KEY VARCHAR(64) NULL, + TASK_ID VARCHAR(40) NULL, + EVENT_TYPE VARCHAR(32) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + DOMAIN VARCHAR(32) NULL, + WORKBASKET_KEY VARCHAR(64) NULL, WORKBASKET_NAME VARCHAR(255) NULL, - POR_COMPANY VARCHAR(32) NULL, - POR_SYSTEM VARCHAR(32) NULL, - POR_INSTANCE VARCHAR(32) NULL, - POR_TYPE VARCHAR(32) NULL, + POR_COMPANY VARCHAR(32) NULL, + POR_SYSTEM VARCHAR(32) NULL, + POR_INSTANCE VARCHAR(32) NULL, + POR_TYPE VARCHAR(32) NULL, POR_VALUE VARCHAR(128) NULL, - TASK_PRIORITY INT NULL, - TASK_PLANNED TIMESTAMP NULL, - TASK_DUE TIMESTAMP NULL, - TASK_OWNER VARCHAR(32) NULL, - TASK_CLASSIFICATION_KEY VARCHAR(32) NULL, - TASK_CLASSIFICATION_NAME VARCHAR(32) NULL, - TASK_CLASSIFICATION_CATEGORY VARCHAR(32) NULL, - ATTACHMENT_CLASSIFICATION_KEY VARCHAR(32) NULL, + TASK_PRIORITY INT NULL, + TASK_PLANNED TIMESTAMP NULL, + TASK_DUE TIMESTAMP NULL, + TASK_OWNER VARCHAR(32) NULL, + TASK_CLASSIFICATION_KEY VARCHAR(32) NULL, + TASK_CLASSIFICATION_NAME VARCHAR(32) NULL, + TASK_CLASSIFICATION_CATEGORY VARCHAR(32) NULL, + ATTACHMENT_CLASSIFICATION_KEY VARCHAR(32) NULL, ATTACHMENT_CLASSIFICATION_NAME VARCHAR(255) NULL, OLD_VALUE VARCHAR(255) NULL, NEW_VALUE VARCHAR(255) NULL, @@ -250,92 +263,94 @@ CREATE TABLE TASK_HISTORY_EVENT ( CUSTOM_2 VARCHAR(128) NULL, CUSTOM_3 VARCHAR(128) NULL, CUSTOM_4 VARCHAR(128) NULL, - DETAILS CLOB NULL, + DETAILS CLOB NULL, PRIMARY KEY (ID) ); CREATE TABLE WORKBASKET_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, - EVENT_TYPE VARCHAR(40) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - DOMAIN VARCHAR(32) NULL, - WORKBASKET_ID VARCHAR(40) NULL, - KEY VARCHAR(64) NULL, - TYPE VARCHAR(64) NULL, - OWNER VARCHAR(128) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - ORGLEVEL_1 VARCHAR(255) NULL, - ORGLEVEL_2 VARCHAR(255) NULL, - ORGLEVEL_3 VARCHAR(255) NULL, - ORGLEVEL_4 VARCHAR(255) NULL, - DETAILS CLOB NULL, + ID VARCHAR(40) NOT NULL, + EVENT_TYPE VARCHAR(40) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + DOMAIN VARCHAR(32) NULL, + WORKBASKET_ID VARCHAR(40) NULL, + KEY VARCHAR(64) NULL, + TYPE VARCHAR(64) NULL, + OWNER VARCHAR(128) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + ORGLEVEL_1 VARCHAR(255) NULL, + ORGLEVEL_2 VARCHAR(255) NULL, + ORGLEVEL_3 VARCHAR(255) NULL, + ORGLEVEL_4 VARCHAR(255) NULL, + DETAILS CLOB NULL, PRIMARY KEY (ID) ); CREATE TABLE CLASSIFICATION_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, - EVENT_TYPE VARCHAR(40) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - APPLICATION_ENTRY_POINT VARCHAR(255) NULL, - CATEGORY VARCHAR(64) NULL, - DOMAIN VARCHAR(32) NULL, - KEY VARCHAR(40) NULL, - NAME VARCHAR(255) NULL, - PARENT_ID VARCHAR(40) NOT NULL, - PARENT_KEY VARCHAR(32) NOT NULL, - PRIORITY INT NOT NULL, - SERVICE_LEVEL VARCHAR(255) NULL, - TYPE VARCHAR(32), - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, - DETAILS CLOB NULL, + ID VARCHAR(40) NOT NULL, + EVENT_TYPE VARCHAR(40) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + APPLICATION_ENTRY_POINT VARCHAR(255) NULL, + CATEGORY VARCHAR(64) NULL, + DOMAIN VARCHAR(32) NULL, + KEY VARCHAR(40) NULL, + NAME VARCHAR(255) NULL, + PARENT_ID VARCHAR(40) NOT NULL, + PARENT_KEY VARCHAR(32) NOT NULL, + PRIORITY INT NOT NULL, + SERVICE_LEVEL VARCHAR(255) NULL, + TYPE VARCHAR(32), + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, + DETAILS CLOB NULL, PRIMARY KEY (ID) ); -CREATE TABLE CONFIGURATION ( - NAME VARCHAR(8) NOT NULL, - ENFORCE_SECURITY BOOLEAN NULL, +CREATE TABLE CONFIGURATION +( + NAME VARCHAR(8) NOT NULL, + ENFORCE_SECURITY BOOLEAN NULL, CUSTOM_ATTRIBUTES CLOB NULL, PRIMARY KEY (NAME) ); -INSERT INTO CONFIGURATION (NAME) VALUES ('MASTER'); +INSERT INTO CONFIGURATION (NAME) +VALUES ('MASTER'); -CREATE TABLE USER_INFO ( - USER_ID VARCHAR(32) NOT NULL, - FIRST_NAME VARCHAR(32) NULL, - LASTNAME VARCHAR(32) NULL, - FULL_NAME VARCHAR(64) NULL, - LONG_NAME VARCHAR(64) NULL, - E_MAIL VARCHAR(64) NULL, - PHONE VARCHAR(32) NULL, - MOBILE_PHONE VARCHAR(32) NULL, - ORG_LEVEL_4 VARCHAR(32) NULL, - ORG_LEVEL_3 VARCHAR(32) NULL, - ORG_LEVEL_2 VARCHAR(32) NULL, - ORG_LEVEL_1 VARCHAR(32) NULL, - DATA CLOB NULL, +CREATE TABLE USER_INFO +( + USER_ID VARCHAR(32) NOT NULL, + FIRST_NAME VARCHAR(32) NULL, + LASTNAME VARCHAR(32) NULL, + FULL_NAME VARCHAR(64) NULL, + LONG_NAME VARCHAR(64) NULL, + E_MAIL VARCHAR(64) NULL, + PHONE VARCHAR(32) NULL, + MOBILE_PHONE VARCHAR(32) NULL, + ORG_LEVEL_4 VARCHAR(32) NULL, + ORG_LEVEL_3 VARCHAR(32) NULL, + ORG_LEVEL_2 VARCHAR(32) NULL, + ORG_LEVEL_1 VARCHAR(32) NULL, + DATA CLOB NULL, PRIMARY KEY (USER_ID) ); CREATE SEQUENCE SCHEDULED_JOB_SEQ - MINVALUE 1 - START WITH 1 - INCREMENT BY 1 - CACHE 10; + MINVALUE 1 + START WITH 1 + INCREMENT BY 1 CACHE 10; diff --git a/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_4.11.0_to_5.0.0_h2.sql b/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_4.11.0_to_5.0.0_h2.sql index beb987384..9489e98de 100644 --- a/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_4.11.0_to_5.0.0_h2.sql +++ b/common/taskana-common/src/main/resources/sql/h2/taskana_schema_update_4.11.0_to_5.0.0_h2.sql @@ -2,4 +2,4 @@ INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) VALUES ('5.0.0', CURRENT_TIMESTAMP); - +ALTER TABLE OBJECT_REFERENCE ADD COLUMN TASK_ID VARCHAR(40) NOT NULL DEFAULT 'EMPTY'; diff --git a/common/taskana-common/src/main/resources/sql/postgres/taskana-schema-postgres.sql b/common/taskana-common/src/main/resources/sql/postgres/taskana-schema-postgres.sql index 0a7cadf23..50f48212f 100644 --- a/common/taskana-common/src/main/resources/sql/postgres/taskana-schema-postgres.sql +++ b/common/taskana-common/src/main/resources/sql/postgres/taskana-schema-postgres.sql @@ -1,243 +1,257 @@ CREATE SCHEMA IF NOT EXISTS %schemaName%; -SET search_path TO %schemaName%; +SET +search_path TO %schemaName%; -CREATE TABLE TASKANA_SCHEMA_VERSION( - ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), - VERSION VARCHAR(255) NOT NULL, - CREATED TIMESTAMP NOT NULL, - PRIMARY KEY (ID) +CREATE TABLE TASKANA_SCHEMA_VERSION +( + ID INT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1), + VERSION VARCHAR(255) NOT NULL, + CREATED TIMESTAMP NOT NULL, + PRIMARY KEY (ID) ); -- The VERSION value must match the value of TaskanaEngineConfiguration.TASKANA_SCHEMA_VERSION -INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) VALUES ('5.0.0', CURRENT_TIMESTAMP); +INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) +VALUES ('5.0.0', CURRENT_TIMESTAMP); -CREATE TABLE CLASSIFICATION( - ID VARCHAR(40) NOT NULL, - KEY VARCHAR(32) NOT NULL, - PARENT_ID VARCHAR(40) NOT NULL, - PARENT_KEY VARCHAR(32) NOT NULL, - CATEGORY VARCHAR(32), - TYPE VARCHAR(32), - DOMAIN VARCHAR(32) NOT NULL, - VALID_IN_DOMAIN BOOLEAN NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - NAME VARCHAR(255) NULL, - DESCRIPTION VARCHAR(255) NULL, - PRIORITY INT NOT NULL, - SERVICE_LEVEL VARCHAR(255) NULL, +CREATE TABLE CLASSIFICATION +( + ID VARCHAR(40) NOT NULL, + KEY VARCHAR(32) NOT NULL, + PARENT_ID VARCHAR(40) NOT NULL, + PARENT_KEY VARCHAR(32) NOT NULL, + CATEGORY VARCHAR(32), + TYPE VARCHAR(32), + DOMAIN VARCHAR(32) NOT NULL, + VALID_IN_DOMAIN BOOLEAN NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + NAME VARCHAR(255) NULL, + DESCRIPTION VARCHAR(255) NULL, + PRIORITY INT NOT NULL, + SERVICE_LEVEL VARCHAR(255) NULL, APPLICATION_ENTRY_POINT VARCHAR(255) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, PRIMARY KEY (ID), CONSTRAINT UC_CLASS_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); -CREATE TABLE WORKBASKET( - ID VARCHAR(40) NOT NULL, - KEY VARCHAR(64) NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - NAME VARCHAR(255) NOT NULL, - DOMAIN VARCHAR(32) NOT NULL, - TYPE VARCHAR(16) NOT NULL, - DESCRIPTION VARCHAR(255) NULL, - OWNER VARCHAR(128) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - ORG_LEVEL_1 VARCHAR(255) NULL, - ORG_LEVEL_2 VARCHAR(255) NULL, - ORG_LEVEL_3 VARCHAR(255) NULL, - ORG_LEVEL_4 VARCHAR(255) NULL, - MARKED_FOR_DELETION BOOLEAN NOT NULL, +CREATE TABLE WORKBASKET +( + ID VARCHAR(40) NOT NULL, + KEY VARCHAR(64) NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + NAME VARCHAR(255) NOT NULL, + DOMAIN VARCHAR(32) NOT NULL, + TYPE VARCHAR(16) NOT NULL, + DESCRIPTION VARCHAR(255) NULL, + OWNER VARCHAR(128) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + ORG_LEVEL_1 VARCHAR(255) NULL, + ORG_LEVEL_2 VARCHAR(255) NULL, + ORG_LEVEL_3 VARCHAR(255) NULL, + ORG_LEVEL_4 VARCHAR(255) NULL, + MARKED_FOR_DELETION BOOLEAN NOT NULL, PRIMARY KEY (ID), CONSTRAINT WB_KEY_DOMAIN UNIQUE (KEY, DOMAIN) ); -CREATE TABLE TASK ( - ID VARCHAR(40) NOT NULL, - EXTERNAL_ID VARCHAR(64) NOT NULL, - CREATED TIMESTAMP NULL, - CLAIMED TIMESTAMP NULL, - COMPLETED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, - RECEIVED TIMESTAMP NULL, - PLANNED TIMESTAMP NULL, - DUE TIMESTAMP NULL, - NAME VARCHAR(255) NULL, - CREATOR VARCHAR(32) NULL, - DESCRIPTION VARCHAR(1024) NULL, - NOTE VARCHAR(4096) NULL, - PRIORITY INT NULL, - MANUAL_PRIORITY INT NULL, - STATE VARCHAR(20) NULL, - CLASSIFICATION_CATEGORY VARCHAR(32) NULL, - CLASSIFICATION_KEY VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - WORKBASKET_ID VARCHAR(40) NULL, - WORKBASKET_KEY VARCHAR(64) NULL, - DOMAIN VARCHAR(32) NULL, - BUSINESS_PROCESS_ID VARCHAR(128) NULL, - PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, - OWNER VARCHAR(32) NULL, - POR_COMPANY VARCHAR(32) NOT NULL, - POR_SYSTEM VARCHAR(32), - POR_INSTANCE VARCHAR(32), - POR_TYPE VARCHAR(32) NOT NULL, - POR_VALUE VARCHAR(128) NOT NULL, - IS_READ BOOLEAN NOT NULL, - IS_TRANSFERRED BOOLEAN NOT NULL, - CALLBACK_INFO TEXT NULL, - CALLBACK_STATE VARCHAR(30) NULL, - CUSTOM_ATTRIBUTES TEXT NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, - CUSTOM_9 VARCHAR(255) NULL, - CUSTOM_10 VARCHAR(255) NULL, - CUSTOM_11 VARCHAR(255) NULL, - CUSTOM_12 VARCHAR(255) NULL, - CUSTOM_13 VARCHAR(255) NULL, - CUSTOM_14 VARCHAR(255) NULL, - CUSTOM_15 VARCHAR(255) NULL, - CUSTOM_16 VARCHAR(255) NULL, - CUSTOM_INT_1 INT NULL, - CUSTOM_INT_2 INT NULL, - CUSTOM_INT_3 INT NULL, - CUSTOM_INT_4 INT NULL, - CUSTOM_INT_5 INT NULL, - CUSTOM_INT_6 INT NULL, - CUSTOM_INT_7 INT NULL, - CUSTOM_INT_8 INT NULL, - PRIMARY KEY (ID), - CONSTRAINT UC_EXTERNAL_ID UNIQUE (EXTERNAL_ID), - CONSTRAINT TASK_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE NO ACTION, - CONSTRAINT TASK_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION +CREATE TABLE TASK +( + ID VARCHAR(40) NOT NULL, + EXTERNAL_ID VARCHAR(64) NOT NULL, + CREATED TIMESTAMP NULL, + CLAIMED TIMESTAMP NULL, + COMPLETED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, + RECEIVED TIMESTAMP NULL, + PLANNED TIMESTAMP NULL, + DUE TIMESTAMP NULL, + NAME VARCHAR(255) NULL, + CREATOR VARCHAR(32) NULL, + DESCRIPTION VARCHAR(1024) NULL, + NOTE VARCHAR(4096) NULL, + PRIORITY INT NULL, + MANUAL_PRIORITY INT NULL, + STATE VARCHAR(20) NULL, + CLASSIFICATION_CATEGORY VARCHAR(32) NULL, + CLASSIFICATION_KEY VARCHAR(32) NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + WORKBASKET_ID VARCHAR(40) NULL, + WORKBASKET_KEY VARCHAR(64) NULL, + DOMAIN VARCHAR(32) NULL, + BUSINESS_PROCESS_ID VARCHAR(128) NULL, + PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, + OWNER VARCHAR(32) NULL, + POR_COMPANY VARCHAR(32) NOT NULL, + POR_SYSTEM VARCHAR(32), + POR_INSTANCE VARCHAR(32), + POR_TYPE VARCHAR(32) NOT NULL, + POR_VALUE VARCHAR(128) NOT NULL, + IS_READ BOOLEAN NOT NULL, + IS_TRANSFERRED BOOLEAN NOT NULL, + CALLBACK_INFO TEXT NULL, + CALLBACK_STATE VARCHAR(30) NULL, + CUSTOM_ATTRIBUTES TEXT NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, + CUSTOM_9 VARCHAR(255) NULL, + CUSTOM_10 VARCHAR(255) NULL, + CUSTOM_11 VARCHAR(255) NULL, + CUSTOM_12 VARCHAR(255) NULL, + CUSTOM_13 VARCHAR(255) NULL, + CUSTOM_14 VARCHAR(255) NULL, + CUSTOM_15 VARCHAR(255) NULL, + CUSTOM_16 VARCHAR(255) NULL, + CUSTOM_INT_1 INT NULL, + CUSTOM_INT_2 INT NULL, + CUSTOM_INT_3 INT NULL, + CUSTOM_INT_4 INT NULL, + CUSTOM_INT_5 INT NULL, + CUSTOM_INT_6 INT NULL, + CUSTOM_INT_7 INT NULL, + CUSTOM_INT_8 INT NULL, + PRIMARY KEY (ID), + CONSTRAINT UC_EXTERNAL_ID UNIQUE (EXTERNAL_ID), + CONSTRAINT TASK_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE NO ACTION, + CONSTRAINT TASK_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION ); -CREATE TABLE DISTRIBUTION_TARGETS( - SOURCE_ID VARCHAR(40) NOT NULL, - TARGET_ID VARCHAR(40) NOT NULL, - PRIMARY KEY (SOURCE_ID, TARGET_ID) +CREATE TABLE DISTRIBUTION_TARGETS +( + SOURCE_ID VARCHAR(40) NOT NULL, + TARGET_ID VARCHAR(40) NOT NULL, + PRIMARY KEY (SOURCE_ID, TARGET_ID) ); -CREATE TABLE WORKBASKET_ACCESS_LIST( - ID VARCHAR(40) NOT NULL, - WORKBASKET_ID VARCHAR(40) NOT NULL, - ACCESS_ID VARCHAR(255) NOT NULL, - ACCESS_NAME VARCHAR(255) NULL, - PERM_READ BOOLEAN NOT NULL, - PERM_OPEN BOOLEAN NOT NULL, - PERM_APPEND BOOLEAN NOT NULL, - PERM_TRANSFER BOOLEAN NOT NULL, - PERM_DISTRIBUTE BOOLEAN NOT NULL, - PERM_CUSTOM_1 BOOLEAN NOT NULL, - PERM_CUSTOM_2 BOOLEAN NOT NULL, - PERM_CUSTOM_3 BOOLEAN NOT NULL, - PERM_CUSTOM_4 BOOLEAN NOT NULL, - PERM_CUSTOM_5 BOOLEAN NOT NULL, - PERM_CUSTOM_6 BOOLEAN NOT NULL, - PERM_CUSTOM_7 BOOLEAN NOT NULL, - PERM_CUSTOM_8 BOOLEAN NOT NULL, - PERM_CUSTOM_9 BOOLEAN NOT NULL, - PERM_CUSTOM_10 BOOLEAN NOT NULL, - PERM_CUSTOM_11 BOOLEAN NOT NULL, - PERM_CUSTOM_12 BOOLEAN NOT NULL, - PRIMARY KEY (ID), - CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), - CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE +CREATE TABLE WORKBASKET_ACCESS_LIST +( + ID VARCHAR(40) NOT NULL, + WORKBASKET_ID VARCHAR(40) NOT NULL, + ACCESS_ID VARCHAR(255) NOT NULL, + ACCESS_NAME VARCHAR(255) NULL, + PERM_READ BOOLEAN NOT NULL, + PERM_OPEN BOOLEAN NOT NULL, + PERM_APPEND BOOLEAN NOT NULL, + PERM_TRANSFER BOOLEAN NOT NULL, + PERM_DISTRIBUTE BOOLEAN NOT NULL, + PERM_CUSTOM_1 BOOLEAN NOT NULL, + PERM_CUSTOM_2 BOOLEAN NOT NULL, + PERM_CUSTOM_3 BOOLEAN NOT NULL, + PERM_CUSTOM_4 BOOLEAN NOT NULL, + PERM_CUSTOM_5 BOOLEAN NOT NULL, + PERM_CUSTOM_6 BOOLEAN NOT NULL, + PERM_CUSTOM_7 BOOLEAN NOT NULL, + PERM_CUSTOM_8 BOOLEAN NOT NULL, + PERM_CUSTOM_9 BOOLEAN NOT NULL, + PERM_CUSTOM_10 BOOLEAN NOT NULL, + PERM_CUSTOM_11 BOOLEAN NOT NULL, + PERM_CUSTOM_12 BOOLEAN NOT NULL, + PRIMARY KEY (ID), + CONSTRAINT UC_ACCESSID_WBID UNIQUE (ACCESS_ID, WORKBASKET_ID), + CONSTRAINT ACCESS_LIST_WB FOREIGN KEY (WORKBASKET_ID) REFERENCES WORKBASKET ON DELETE CASCADE ); -CREATE TABLE OBJECT_REFERENCE( - ID VARCHAR(40) NOT NULL, - COMPANY VARCHAR(32) NOT NULL, - SYSTEM VARCHAR(32), - SYSTEM_INSTANCE VARCHAR(32), - TYPE VARCHAR(32) NOT NULL, - VALUE VARCHAR(128) NOT NULL +CREATE TABLE OBJECT_REFERENCE +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, + COMPANY VARCHAR(32) NOT NULL, + SYSTEM VARCHAR(32), + SYSTEM_INSTANCE VARCHAR(32), + TYPE VARCHAR(32) NOT NULL, + VALUE VARCHAR(128) NOT NULL ); -CREATE TABLE ATTACHMENT( - ID VARCHAR(40) NOT NULL, - TASK_ID VARCHAR(40) NOT NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, +CREATE TABLE ATTACHMENT +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, CLASSIFICATION_KEY VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - REF_COMPANY VARCHAR(32) NOT NULL, - REF_SYSTEM VARCHAR(32), - REF_INSTANCE VARCHAR(32), - REF_TYPE VARCHAR(32) NOT NULL, - REF_VALUE VARCHAR(128) NOT NULL, - CHANNEL VARCHAR(64) NULL, - RECEIVED TIMESTAMP NULL, - CUSTOM_ATTRIBUTES TEXT NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + REF_COMPANY VARCHAR(32) NOT NULL, + REF_SYSTEM VARCHAR(32), + REF_INSTANCE VARCHAR(32), + REF_TYPE VARCHAR(32) NOT NULL, + REF_VALUE VARCHAR(128) NOT NULL, + CHANNEL VARCHAR(64) NULL, + RECEIVED TIMESTAMP NULL, + CUSTOM_ATTRIBUTES TEXT NULL, PRIMARY KEY (ID), CONSTRAINT ATT_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION ); -CREATE TABLE TASK_COMMENT( - ID VARCHAR(40) NOT NULL, - TASK_ID VARCHAR(40) NOT NULL, +CREATE TABLE TASK_COMMENT +( + ID VARCHAR(40) NOT NULL, + TASK_ID VARCHAR(40) NOT NULL, TEXT_FIELD VARCHAR(1024) NULL, - CREATOR VARCHAR(32) NULL, - CREATED TIMESTAMP NULL, - MODIFIED TIMESTAMP NULL, + CREATOR VARCHAR(32) NULL, + CREATED TIMESTAMP NULL, + MODIFIED TIMESTAMP NULL, PRIMARY KEY (ID), CONSTRAINT COMMENT_TASK FOREIGN KEY (TASK_ID) REFERENCES TASK ON DELETE CASCADE ); -CREATE TABLE SCHEDULED_JOB( - JOB_ID INTEGER NOT NULL, - PRIORITY INTEGER NULL, - CREATED TIMESTAMP NULL, - DUE TIMESTAMP NULL, - STATE VARCHAR(32) NULL, - LOCKED_BY VARCHAR(32) NULL, - LOCK_EXPIRES TIMESTAMP NULL, - TYPE VARCHAR(255) NULL, - RETRY_COUNT INTEGER NOT NULL, - ARGUMENTS TEXT NULL, - PRIMARY KEY (JOB_ID) +CREATE TABLE SCHEDULED_JOB +( + JOB_ID INTEGER NOT NULL, + PRIORITY INTEGER NULL, + CREATED TIMESTAMP NULL, + DUE TIMESTAMP NULL, + STATE VARCHAR(32) NULL, + LOCKED_BY VARCHAR(32) NULL, + LOCK_EXPIRES TIMESTAMP NULL, + TYPE VARCHAR(255) NULL, + RETRY_COUNT INTEGER NOT NULL, + ARGUMENTS TEXT NULL, + PRIMARY KEY (JOB_ID) ); -CREATE TABLE TASK_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, +CREATE TABLE TASK_HISTORY_EVENT +( + ID VARCHAR(40) NOT NULL, BUSINESS_PROCESS_ID VARCHAR(128) NULL, PARENT_BUSINESS_PROCESS_ID VARCHAR(128) NULL, - TASK_ID VARCHAR(40) NULL, - EVENT_TYPE VARCHAR(32) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - DOMAIN VARCHAR(32) NULL, - WORKBASKET_KEY VARCHAR(64) NULL, + TASK_ID VARCHAR(40) NULL, + EVENT_TYPE VARCHAR(32) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + DOMAIN VARCHAR(32) NULL, + WORKBASKET_KEY VARCHAR(64) NULL, WORKBASKET_NAME VARCHAR(255) NULL, - POR_COMPANY VARCHAR(32) NULL, - POR_SYSTEM VARCHAR(32) NULL, - POR_INSTANCE VARCHAR(32) NULL, - POR_TYPE VARCHAR(32) NULL, + POR_COMPANY VARCHAR(32) NULL, + POR_SYSTEM VARCHAR(32) NULL, + POR_INSTANCE VARCHAR(32) NULL, + POR_TYPE VARCHAR(32) NULL, POR_VALUE VARCHAR(128) NULL, - TASK_PRIORITY INT NULL, - TASK_PLANNED TIMESTAMP NULL, - TASK_DUE TIMESTAMP NULL, - TASK_OWNER VARCHAR(32) NULL, - TASK_CLASSIFICATION_KEY VARCHAR(32) NULL, - TASK_CLASSIFICATION_NAME VARCHAR(32) NULL, - TASK_CLASSIFICATION_CATEGORY VARCHAR(32) NULL, - ATTACHMENT_CLASSIFICATION_KEY VARCHAR(32) NULL, + TASK_PRIORITY INT NULL, + TASK_PLANNED TIMESTAMP NULL, + TASK_DUE TIMESTAMP NULL, + TASK_OWNER VARCHAR(32) NULL, + TASK_CLASSIFICATION_KEY VARCHAR(32) NULL, + TASK_CLASSIFICATION_NAME VARCHAR(32) NULL, + TASK_CLASSIFICATION_CATEGORY VARCHAR(32) NULL, + ATTACHMENT_CLASSIFICATION_KEY VARCHAR(32) NULL, ATTACHMENT_CLASSIFICATION_NAME VARCHAR(255) NULL, OLD_VALUE VARCHAR(255) NULL, NEW_VALUE VARCHAR(255) NULL, @@ -245,163 +259,166 @@ CREATE TABLE TASK_HISTORY_EVENT ( CUSTOM_2 VARCHAR(128) NULL, CUSTOM_3 VARCHAR(128) NULL, CUSTOM_4 VARCHAR(128) NULL, - DETAILS TEXT NULL, + DETAILS TEXT NULL, PRIMARY KEY (ID) ); CREATE TABLE WORKBASKET_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, - WORKBASKET_ID VARCHAR(40) NULL, - EVENT_TYPE VARCHAR(40) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - DOMAIN VARCHAR(32) NULL, - KEY VARCHAR(64) NULL, - TYPE VARCHAR(64) NULL, - OWNER VARCHAR(128) NULL, - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - ORGLEVEL_1 VARCHAR(255) NULL, - ORGLEVEL_2 VARCHAR(255) NULL, - ORGLEVEL_3 VARCHAR(255) NULL, - ORGLEVEL_4 VARCHAR(255) NULL, - DETAILS TEXT NULL, + ID VARCHAR(40) NOT NULL, + WORKBASKET_ID VARCHAR(40) NULL, + EVENT_TYPE VARCHAR(40) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + DOMAIN VARCHAR(32) NULL, + KEY VARCHAR(64) NULL, + TYPE VARCHAR(64) NULL, + OWNER VARCHAR(128) NULL, + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + ORGLEVEL_1 VARCHAR(255) NULL, + ORGLEVEL_2 VARCHAR(255) NULL, + ORGLEVEL_3 VARCHAR(255) NULL, + ORGLEVEL_4 VARCHAR(255) NULL, + DETAILS TEXT NULL, PRIMARY KEY (ID) ); CREATE TABLE CLASSIFICATION_HISTORY_EVENT ( - ID VARCHAR(40) NOT NULL, - EVENT_TYPE VARCHAR(40) NULL, - CREATED TIMESTAMP NULL, - USER_ID VARCHAR(32) NULL, - CLASSIFICATION_ID VARCHAR(40) NULL, - APPLICATION_ENTRY_POINT VARCHAR(255) NULL, - CATEGORY VARCHAR(64) NULL, - DOMAIN VARCHAR(32) NULL, - KEY VARCHAR(40) NULL, - NAME VARCHAR(255) NULL, - PARENT_ID VARCHAR(40) NOT NULL, - PARENT_KEY VARCHAR(32) NOT NULL, - PRIORITY INT NOT NULL, - SERVICE_LEVEL VARCHAR(255) NULL, - TYPE VARCHAR(32), - CUSTOM_1 VARCHAR(255) NULL, - CUSTOM_2 VARCHAR(255) NULL, - CUSTOM_3 VARCHAR(255) NULL, - CUSTOM_4 VARCHAR(255) NULL, - CUSTOM_5 VARCHAR(255) NULL, - CUSTOM_6 VARCHAR(255) NULL, - CUSTOM_7 VARCHAR(255) NULL, - CUSTOM_8 VARCHAR(255) NULL, - DETAILS TEXT NULL, + ID VARCHAR(40) NOT NULL, + EVENT_TYPE VARCHAR(40) NULL, + CREATED TIMESTAMP NULL, + USER_ID VARCHAR(32) NULL, + CLASSIFICATION_ID VARCHAR(40) NULL, + APPLICATION_ENTRY_POINT VARCHAR(255) NULL, + CATEGORY VARCHAR(64) NULL, + DOMAIN VARCHAR(32) NULL, + KEY VARCHAR(40) NULL, + NAME VARCHAR(255) NULL, + PARENT_ID VARCHAR(40) NOT NULL, + PARENT_KEY VARCHAR(32) NOT NULL, + PRIORITY INT NOT NULL, + SERVICE_LEVEL VARCHAR(255) NULL, + TYPE VARCHAR(32), + CUSTOM_1 VARCHAR(255) NULL, + CUSTOM_2 VARCHAR(255) NULL, + CUSTOM_3 VARCHAR(255) NULL, + CUSTOM_4 VARCHAR(255) NULL, + CUSTOM_5 VARCHAR(255) NULL, + CUSTOM_6 VARCHAR(255) NULL, + CUSTOM_7 VARCHAR(255) NULL, + CUSTOM_8 VARCHAR(255) NULL, + DETAILS TEXT NULL, PRIMARY KEY (ID) ); -CREATE TABLE CONFIGURATION ( - NAME VARCHAR(8) NOT NULL, - ENFORCE_SECURITY BOOLEAN NULL, +CREATE TABLE CONFIGURATION +( + NAME VARCHAR(8) NOT NULL, + ENFORCE_SECURITY BOOLEAN NULL, CUSTOM_ATTRIBUTES TEXT NULL, PRIMARY KEY (NAME) ); -INSERT INTO CONFIGURATION (NAME) VALUES ('MASTER'); +INSERT INTO CONFIGURATION (NAME) +VALUES ('MASTER'); -CREATE TABLE USER_INFO ( - USER_ID VARCHAR(32) NOT NULL, - FIRST_NAME VARCHAR(32) NULL, - LASTNAME VARCHAR(32) NULL, - FULL_NAME VARCHAR(64) NULL, - LONG_NAME VARCHAR(64) NULL, - E_MAIL VARCHAR(64) NULL, - PHONE VARCHAR(32) NULL, - MOBILE_PHONE VARCHAR(32) NULL, - ORG_LEVEL_4 VARCHAR(32) NULL, - ORG_LEVEL_3 VARCHAR(32) NULL, - ORG_LEVEL_2 VARCHAR(32) NULL, - ORG_LEVEL_1 VARCHAR(32) NULL, - DATA TEXT NULL, +CREATE TABLE USER_INFO +( + USER_ID VARCHAR(32) NOT NULL, + FIRST_NAME VARCHAR(32) NULL, + LASTNAME VARCHAR(32) NULL, + FULL_NAME VARCHAR(64) NULL, + LONG_NAME VARCHAR(64) NULL, + E_MAIL VARCHAR(64) NULL, + PHONE VARCHAR(32) NULL, + MOBILE_PHONE VARCHAR(32) NULL, + ORG_LEVEL_4 VARCHAR(32) NULL, + ORG_LEVEL_3 VARCHAR(32) NULL, + ORG_LEVEL_2 VARCHAR(32) NULL, + ORG_LEVEL_1 VARCHAR(32) NULL, + DATA TEXT NULL, PRIMARY KEY (USER_ID) ); CREATE SEQUENCE SCHEDULED_JOB_SEQ - MINVALUE 1 - START WITH 1 - INCREMENT BY 1 - CACHE 10; + MINVALUE 1 + START WITH 1 + INCREMENT BY 1 CACHE 10; - SET search_path TO taskana; +SET +search_path TO taskana; - CREATE INDEX IDX_CLASSIFICATION_ID ON CLASSIFICATION - (ID ASC, CUSTOM_8, CUSTOM_7, CUSTOM_6, CUSTOM_5, CUSTOM_4, - CUSTOM_3, CUSTOM_2, CUSTOM_1, APPLICATION_ENTRY_POINT, - SERVICE_LEVEL, PRIORITY, DESCRIPTION, NAME, MODIFIED, - CREATED, VALID_IN_DOMAIN, DOMAIN, TYPE, CATEGORY, PARENT_KEY, - PARENT_ID, KEY); - COMMIT WORK ; - CREATE INDEX IDX_CLASSIFICATION_CATEGORY ON CLASSIFICATION - (CATEGORY ASC, DOMAIN ASC, TYPE ASC, CUSTOM_1 - ASC, CUSTOM_8 ASC, CUSTOM_7 ASC, CUSTOM_6 ASC, - CUSTOM_5 ASC, CUSTOM_4 ASC, CUSTOM_3 ASC, CUSTOM_2 - ASC, APPLICATION_ENTRY_POINT ASC, SERVICE_LEVEL - ASC, PRIORITY ASC, DESCRIPTION ASC, NAME ASC, - CREATED ASC, VALID_IN_DOMAIN ASC, PARENT_KEY ASC, PARENT_ID - ASC, KEY ASC, ID ASC); - COMMIT WORK ; - CREATE INDEX IDX_CLASSIFICATION_KEY_DOMAIN ON CLASSIFICATION - (KEY ASC, DOMAIN ASC, CUSTOM_8, CUSTOM_7, CUSTOM_6, - CUSTOM_5, CUSTOM_4, CUSTOM_3, CUSTOM_2, CUSTOM_1, - APPLICATION_ENTRY_POINT, SERVICE_LEVEL, PRIORITY, - DESCRIPTION, NAME, CREATED, VALID_IN_DOMAIN, - TYPE, CATEGORY, PARENT_KEY, PARENT_ID, ID) ; - COMMIT WORK ; +CREATE INDEX IDX_CLASSIFICATION_ID ON CLASSIFICATION + (ID ASC, CUSTOM_8, CUSTOM_7, CUSTOM_6, CUSTOM_5, CUSTOM_4, + CUSTOM_3, CUSTOM_2, CUSTOM_1, APPLICATION_ENTRY_POINT, + SERVICE_LEVEL, PRIORITY, DESCRIPTION, NAME, MODIFIED, + CREATED, VALID_IN_DOMAIN, DOMAIN, TYPE, CATEGORY, PARENT_KEY, + PARENT_ID, KEY); +COMMIT WORK; +CREATE INDEX IDX_CLASSIFICATION_CATEGORY ON CLASSIFICATION + (CATEGORY ASC, DOMAIN ASC, TYPE ASC, CUSTOM_1 + ASC, CUSTOM_8 ASC, CUSTOM_7 ASC, CUSTOM_6 ASC, + CUSTOM_5 ASC, CUSTOM_4 ASC, CUSTOM_3 ASC, CUSTOM_2 + ASC, APPLICATION_ENTRY_POINT ASC, SERVICE_LEVEL + ASC, PRIORITY ASC, DESCRIPTION ASC, NAME ASC, + CREATED ASC, VALID_IN_DOMAIN ASC, PARENT_KEY ASC, PARENT_ID + ASC, KEY ASC, ID ASC); +COMMIT WORK; +CREATE INDEX IDX_CLASSIFICATION_KEY_DOMAIN ON CLASSIFICATION + (KEY ASC, DOMAIN ASC, CUSTOM_8, CUSTOM_7, CUSTOM_6, + CUSTOM_5, CUSTOM_4, CUSTOM_3, CUSTOM_2, CUSTOM_1, + APPLICATION_ENTRY_POINT, SERVICE_LEVEL, PRIORITY, + DESCRIPTION, NAME, CREATED, VALID_IN_DOMAIN, + TYPE, CATEGORY, PARENT_KEY, PARENT_ID, ID); +COMMIT WORK; - CREATE INDEX IDX_TASK_WORKBASKET_KEY_DOMAIN ON TASK - (WORKBASKET_KEY ASC, DOMAIN DESC); - COMMIT WORK ; - CREATE INDEX IDX_TASK_POR_VALUE ON TASK - (UPPER(POR_VALUE) ASC, WORKBASKET_ID ASC); - COMMIT WORK ; +CREATE INDEX IDX_TASK_WORKBASKET_KEY_DOMAIN ON TASK + (WORKBASKET_KEY ASC, DOMAIN DESC); +COMMIT WORK; +CREATE INDEX IDX_TASK_POR_VALUE ON TASK + (UPPER(POR_VALUE) ASC, WORKBASKET_ID ASC); +COMMIT WORK; - CREATE INDEX IDX_ATTACHMENT_TASK_ID ON ATTACHMENT - (TASK_ID ASC, RECEIVED ASC, CLASSIFICATION_ID - ASC, CLASSIFICATION_KEY ASC, MODIFIED ASC, CREATED - ASC, ID ASC) ; - COMMIT WORK ; +CREATE INDEX IDX_ATTACHMENT_TASK_ID ON ATTACHMENT + (TASK_ID ASC, RECEIVED ASC, CLASSIFICATION_ID + ASC, CLASSIFICATION_KEY ASC, MODIFIED ASC, CREATED + ASC, ID ASC); +COMMIT WORK; - CREATE INDEX IDX_WORKBASKET_ID ON WORKBASKET - (ID ASC, ORG_LEVEL_4, ORG_LEVEL_3, ORG_LEVEL_2, - ORG_LEVEL_1, OWNER, DESCRIPTION, TYPE, DOMAIN, NAME, KEY); - COMMIT WORK ; - CREATE INDEX IDX_WORKBASKET_KEY_DOMAIN ON WORKBASKET - (KEY ASC, DOMAIN ASC, ORG_LEVEL_4, - ORG_LEVEL_3, ORG_LEVEL_2, ORG_LEVEL_1, CUSTOM_4, - CUSTOM_3, CUSTOM_2, CUSTOM_1, OWNER, DESCRIPTION, - TYPE, NAME, MODIFIED, CREATED, ID) ; - COMMIT WORK ; - CREATE INDEX IDX_WORKBASKET_KEY_DOMAIN_ID ON WORKBASKET - (KEY ASC, DOMAIN ASC, ID) ; - COMMIT WORK ; +CREATE INDEX IDX_WORKBASKET_ID ON WORKBASKET + (ID ASC, ORG_LEVEL_4, ORG_LEVEL_3, ORG_LEVEL_2, + ORG_LEVEL_1, OWNER, DESCRIPTION, TYPE, DOMAIN, NAME, KEY); +COMMIT WORK; +CREATE INDEX IDX_WORKBASKET_KEY_DOMAIN ON WORKBASKET + (KEY ASC, DOMAIN ASC, ORG_LEVEL_4, + ORG_LEVEL_3, ORG_LEVEL_2, ORG_LEVEL_1, CUSTOM_4, + CUSTOM_3, CUSTOM_2, CUSTOM_1, OWNER, DESCRIPTION, + TYPE, NAME, MODIFIED, CREATED, ID); +COMMIT WORK; +CREATE INDEX IDX_WORKBASKET_KEY_DOMAIN_ID ON WORKBASKET + (KEY ASC, DOMAIN ASC, ID); +COMMIT WORK; - CREATE INDEX IDX_WORKBASKET_ACCESS_LIST_ACCESS_ID ON WORKBASKET_ACCESS_LIST - (ACCESS_ID ASC, WORKBASKET_ID ASC, PERM_READ ASC) ; - COMMIT WORK ; - CREATE INDEX IDX_WORKBASKET_ACCESS_LIST_WORKBASKET_ID ON WORKBASKET_ACCESS_LIST - (WORKBASKET_ID ASC, PERM_CUSTOM_12 ASC, PERM_CUSTOM_11 - ASC, PERM_CUSTOM_10 ASC, PERM_CUSTOM_9 ASC, PERM_CUSTOM_8 - ASC, PERM_CUSTOM_7 ASC, PERM_CUSTOM_6 ASC, PERM_CUSTOM_5 - ASC, PERM_CUSTOM_4 ASC, PERM_CUSTOM_3 ASC, PERM_CUSTOM_2 - ASC, PERM_CUSTOM_1 ASC, PERM_DISTRIBUTE ASC, PERM_TRANSFER - ASC, PERM_APPEND ASC, PERM_OPEN ASC, PERM_READ - ASC, ACCESS_ID ASC) ; - COMMIT WORK ; +CREATE INDEX IDX_WORKBASKET_ACCESS_LIST_ACCESS_ID ON WORKBASKET_ACCESS_LIST + (ACCESS_ID ASC, WORKBASKET_ID ASC, PERM_READ ASC); +COMMIT WORK; +CREATE INDEX IDX_WORKBASKET_ACCESS_LIST_WORKBASKET_ID ON WORKBASKET_ACCESS_LIST + (WORKBASKET_ID ASC, PERM_CUSTOM_12 ASC, PERM_CUSTOM_11 + ASC, PERM_CUSTOM_10 ASC, PERM_CUSTOM_9 ASC, PERM_CUSTOM_8 + ASC, PERM_CUSTOM_7 ASC, PERM_CUSTOM_6 ASC, PERM_CUSTOM_5 + ASC, PERM_CUSTOM_4 ASC, PERM_CUSTOM_3 ASC, PERM_CUSTOM_2 + ASC, PERM_CUSTOM_1 ASC, PERM_DISTRIBUTE ASC, PERM_TRANSFER + ASC, PERM_APPEND ASC, PERM_OPEN ASC, PERM_READ + ASC, ACCESS_ID ASC); +COMMIT WORK; diff --git a/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_4.11.0_to_5.0.0_postgres.sql b/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_4.11.0_to_5.0.0_postgres.sql index 374cf63dd..ccdb16a13 100644 --- a/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_4.11.0_to_5.0.0_postgres.sql +++ b/common/taskana-common/src/main/resources/sql/postgres/taskana_schema_update_4.11.0_to_5.0.0_postgres.sql @@ -4,6 +4,8 @@ SET search_path = %schemaName%; INSERT INTO TASKANA_SCHEMA_VERSION (VERSION, CREATED) VALUES ('5.0.0', CURRENT_TIMESTAMP); +ALTER TABLE OBJECT_REFERENCE ADD COLUMN TASK_ID VARCHAR(40) NOT NULL DEFAULT 'EMPTY'; + DROP INDEX IF EXISTS IDX_CLASSIFICATION_1; CREATE INDEX IDX_CLASSIFICATION_ID ON CLASSIFICATION (ID ASC, CUSTOM_8, CUSTOM_7, CUSTOM_6, CUSTOM_5, CUSTOM_4, diff --git a/history/taskana-simplehistory-provider/src/test/java/acceptance/AbstractAccTest.java b/history/taskana-simplehistory-provider/src/test/java/acceptance/AbstractAccTest.java index 81f6adc98..2b5002fbb 100644 --- a/history/taskana-simplehistory-provider/src/test/java/acceptance/AbstractAccTest.java +++ b/history/taskana-simplehistory-provider/src/test/java/acceptance/AbstractAccTest.java @@ -30,6 +30,7 @@ import pro.taskana.simplehistory.impl.workbasket.WorkbasketHistoryEventMapper; import pro.taskana.spi.history.api.events.task.TaskHistoryEvent; import pro.taskana.spi.history.api.events.workbasket.WorkbasketHistoryEvent; import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.internal.models.ObjectReferenceImpl; /** Set up database for tests. */ public abstract class AbstractAccTest { @@ -184,7 +185,7 @@ public abstract class AbstractAccTest { protected ObjectReference createObjectRef( String company, String system, String systemInstance, String type, String value) { - ObjectReference objectRef = new ObjectReference(); + ObjectReferenceImpl objectRef = new ObjectReferenceImpl(); objectRef.setCompany(company); objectRef.setSystem(system); objectRef.setSystemInstance(systemInstance); diff --git a/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleBootstrap.java b/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleBootstrap.java index c846d6f88..dfc454f68 100644 --- a/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleBootstrap.java +++ b/lib/taskana-cdi-example/src/main/java/pro/taskana/example/ExampleBootstrap.java @@ -12,10 +12,11 @@ import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; import pro.taskana.task.api.exceptions.InvalidOwnerException; import pro.taskana.task.api.exceptions.InvalidStateException; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskNotFoundException; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; /** Example Bootstrap Application. */ @@ -28,9 +29,10 @@ public class ExampleBootstrap { public void init(@Observes @Initialized(ApplicationScoped.class) Object init) throws TaskNotFoundException, NotAuthorizedException, WorkbasketNotFoundException, ClassificationNotFoundException, InvalidStateException, InvalidOwnerException, - TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException { + TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, + ObjectReferencePersistenceException { System.out.println("---------------------------> Start App"); - ObjectReference objRef = new ObjectReference(); + ObjectReferenceImpl objRef = new ObjectReferenceImpl(); objRef.setCompany("aCompany"); objRef.setSystem("aSystem"); objRef.setSystemInstance("anInstance"); diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaCdiTestRestController.java b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaCdiTestRestController.java index e9a0b1446..dc2a19f31 100644 --- a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaCdiTestRestController.java +++ b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaCdiTestRestController.java @@ -13,8 +13,8 @@ import org.slf4j.LoggerFactory; import pro.taskana.classification.api.ClassificationService; import pro.taskana.classification.api.models.Classification; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.workbasket.api.WorkbasketType; import pro.taskana.workbasket.api.models.Workbasket; @@ -39,7 +39,7 @@ public class TaskanaCdiTestRestController { Task task = taskanaEjb.getTaskService().newTask(workbasket.getKey()); task.setClassificationKey(classification.getKey()); - ObjectReference objRef = new ObjectReference(); + ObjectReferenceImpl objRef = new ObjectReferenceImpl(); objRef.setCompany("aCompany"); objRef.setSystem("aSystem"); objRef.setSystemInstance("anInstance"); diff --git a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java index e78206e7a..35332b0ca 100644 --- a/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java +++ b/lib/taskana-cdi/src/test/java/pro/taskana/TaskanaEjb.java @@ -9,9 +9,10 @@ import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.workbasket.api.WorkbasketService; import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; @@ -38,9 +39,10 @@ public class TaskanaEjb { public void triggerRollback() throws NotAuthorizedException, WorkbasketNotFoundException, ClassificationNotFoundException, - TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException { + TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, + ObjectReferencePersistenceException { final Task task = taskService.newTask(null); - ObjectReference objRef = new ObjectReference(); + ObjectReferenceImpl objRef = new ObjectReferenceImpl(); objRef.setCompany("aCompany"); objRef.setSystem("aSystem"); objRef.setSystemInstance("anInstance"); diff --git a/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java b/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java index 4ae640e0c..84abd9e72 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/common/internal/TaskanaEngineImpl.java @@ -144,6 +144,7 @@ public class TaskanaEngineImpl implements TaskanaEngine { sessionManager.getMapper(TaskMapper.class), sessionManager.getMapper(TaskCommentMapper.class), sessionManager.getMapper(AttachmentMapper.class), + sessionManager.getMapper(ObjectReferenceMapper.class), sessionManager.getMapper(UserMapper.class)); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskQuery.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskQuery.java index afbdc855e..11890ae49 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskQuery.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskQuery.java @@ -1458,6 +1458,50 @@ public interface TaskQuery extends BaseQuery { TaskQuery orderByAttachmentReceived(SortDirection sortDirection); // endregion + // region secondaryObjectReference + + /** + * Add the {@link ObjectReference} to exact match to your query. Each individual value has to + * match. Fields with the value 'null' will be ignored. The id of each ObjectReference will be + * ignored + * + *

If you specify multiple arguments they are combined with the OR keyword. + * + * @param objectReferences the combined values which are searched together. + * @return the query + */ + TaskQuery secondaryObjectReferenceIn(ObjectReference... objectReferences); + + // endregion + // region secondaryObjectReferenceCompany + TaskQuery sorCompanyIn(String... companyIn); + + TaskQuery sorCompanyLike(String... companyLike); + + // endregion + // region secondaryObjectReferenceSystem + TaskQuery sorSystemIn(String... systemIn); + + TaskQuery sorSystemLike(String... systemLike); + + // endregion + // region secondaryObjectReferenceSystemInstance + TaskQuery sorSystemInstanceIn(String... systemInstanceIn); + + TaskQuery sorSystemInstanceLike(String... systemInstanceLike); + + // endregion + // region secondaryObjectReferenceType + TaskQuery sorTypeIn(String... typeIn); + + TaskQuery sorTypeLike(String... typeLike); + + // endregion + // region secondaryObjectReferenceValue + TaskQuery sorValueIn(String... valueIn); + + TaskQuery sorValueLike(String... valueLike); + // region customAttributes /** diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskQueryColumnName.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskQueryColumnName.java index 3ecf0b05b..4bbb8785a 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskQueryColumnName.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskQueryColumnName.java @@ -57,7 +57,12 @@ public enum TaskQueryColumnName implements QueryColumnName { A_CLASSIFICATION_ID("a.classification_id"), A_CLASSIFICATION_KEY("a.classification_key"), A_CHANNEL("a.channel"), - A_REF_VALUE("a.ref_value"); + A_REF_VALUE("a.ref_value"), + O_COMPANY("o.company"), + O_SYSTEM("o.system"), + O_SYSTEM_INSTANCE("o.system_instance"), + O_TYPE("o.type"), + O_VALUE("o.value"); private final String name; @@ -69,6 +74,10 @@ public enum TaskQueryColumnName implements QueryColumnName { return this.name().startsWith("A_"); } + public boolean isObjectReferenceColumn() { + return this.name().startsWith("O_"); + } + @Override public String toString() { return name; diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java index 9f1515c9c..9decc1385 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/TaskService.java @@ -13,6 +13,7 @@ import pro.taskana.common.api.exceptions.TaskanaException; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; import pro.taskana.task.api.exceptions.InvalidOwnerException; import pro.taskana.task.api.exceptions.InvalidStateException; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskCommentNotFoundException; import pro.taskana.task.api.exceptions.TaskNotFoundException; @@ -145,10 +146,13 @@ public interface TaskService { * @throws InvalidArgumentException thrown if the primary ObjectReference is invalid * @throws AttachmentPersistenceException if an Attachment with ID will be added multiple times * without using the task-methods + * @throws ObjectReferencePersistenceException if an ObjectReference with ID will be added + * multiple times without using the task-methods */ Task createTask(Task taskToCreate) throws NotAuthorizedException, WorkbasketNotFoundException, ClassificationNotFoundException, - TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException; + TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, + ObjectReferencePersistenceException; /** * Gets the details of a task by Id without checking permissions. @@ -312,6 +316,16 @@ public interface TaskService { */ Attachment newAttachment(); + /** + * Returns a not inserted instance of {@link ObjectReference}. + * + * @return an empty new ObjectReference + */ + ObjectReference newObjectReference(); + + ObjectReference newObjectReference( + String company, String system, String systemInstance, String type, String value); + /** * Update a task. * @@ -326,13 +340,15 @@ public interface TaskService { * @throws NotAuthorizedException if the current user is not authorized to update the task * @throws AttachmentPersistenceException if an Attachment with ID will be added multiple times * without using the task-methods + * @throws ObjectReferencePersistenceException if an ObjectReference with ID will be added + * multiple times without using the task-methods * @throws InvalidStateException if an attempt is made to change the owner of the task and the * task is not in state READY . */ Task updateTask(Task task) throws InvalidArgumentException, TaskNotFoundException, ConcurrencyException, ClassificationNotFoundException, NotAuthorizedException, AttachmentPersistenceException, - InvalidStateException; + ObjectReferencePersistenceException, InvalidStateException; /** * Transfers a list of {@linkplain Task Tasks} to another {@linkplain diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/exceptions/ObjectReferencePersistenceException.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/exceptions/ObjectReferencePersistenceException.java new file mode 100644 index 000000000..8e20c6be6 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/exceptions/ObjectReferencePersistenceException.java @@ -0,0 +1,42 @@ +package pro.taskana.task.api.exceptions; + +import pro.taskana.common.api.exceptions.ErrorCode; +import pro.taskana.common.api.exceptions.TaskanaException; +import pro.taskana.common.internal.util.MapCreator; +import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.api.models.Task; + +/** + * This exception is thrown when an {@linkplain ObjectReference} should be inserted to the DB, but + * it does already exist.
+ * This may happen when a not inserted {@linkplain ObjectReference} with the same {@linkplain + * ObjectReference#getId() id} will be added twice on a {@linkplain Task}. This can't happen if the + * correct {@linkplain Task}-Methods will be used instead of the List ones. + */ +public class ObjectReferencePersistenceException extends TaskanaException { + public static final String ERROR_KEY = "OBJECT_REFERENCE_ALREADY_EXISTS"; + private final String objectReferenceId; + private final String taskId; + + public ObjectReferencePersistenceException( + String objectReferenceId, String taskId, Throwable cause) { + super( + String.format( + "Cannot insert ObjectReference with id '%s' for Task with id '%s' " + + "because it already exists.", + objectReferenceId, taskId), + ErrorCode.of( + ERROR_KEY, MapCreator.of("objectReferenceId", objectReferenceId, "taskId", taskId)), + cause); + this.objectReferenceId = objectReferenceId; + this.taskId = taskId; + } + + public String getObjectReferenceId() { + return objectReferenceId; + } + + public String getTaskId() { + return taskId; + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/models/ObjectReference.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/models/ObjectReference.java index cdc55c9e3..c49c85a96 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/models/ObjectReference.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/models/ObjectReference.java @@ -1,135 +1,96 @@ package pro.taskana.task.api.models; -import java.util.Objects; +/** ObjectReference-Interface to specify ObjectReference Attributes. */ +public interface ObjectReference { -import pro.taskana.common.api.exceptions.InvalidArgumentException; + /** + * Gets the id of the ObjectReference. + * + * @return the id of the ObjectReference. + */ + String getId(); -/** ObjectReference entity. */ -public class ObjectReference { - private String id; - private String company; - private String system; - private String systemInstance; - private String type; - private String value; + /** + * Gets the id of the associated task. + * + * @return the taskId + */ + String getTaskId(); - public ObjectReference() {} + /** + * Gets the company of the ObjectReference. + * + * @return the company + */ + String getCompany(); - private ObjectReference(ObjectReference copyFrom) { - company = copyFrom.company; - system = copyFrom.system; - systemInstance = copyFrom.systemInstance; - type = copyFrom.type; - value = copyFrom.value; - } + /** + * Sets the company of the ObjectReference. + * + * @param company the company of the object reference + */ + void setCompany(String company); - public static void validate(ObjectReference objectReference, String objRefType, String objName) - throws InvalidArgumentException { - // check that all values in the ObjectReference are set correctly - if (objectReference == null) { - throw new InvalidArgumentException( - String.format("%s of %s must not be null.", objRefType, objName)); - } else if (objectReference.getCompany() == null || objectReference.getCompany().isEmpty()) { - throw new InvalidArgumentException( - String.format("Company of %s of %s must not be empty", objRefType, objName)); - } else if (objectReference.getType() == null || objectReference.getType().length() == 0) { - throw new InvalidArgumentException( - String.format("Type of %s of %s must not be empty", objRefType, objName)); - } else if (objectReference.getValue() == null || objectReference.getValue().length() == 0) { - throw new InvalidArgumentException( - String.format("Value of %s of %s must not be empty", objRefType, objName)); - } - } + /** + * Gets the system of the ObjectReference. + * + * @return the system + */ + String getSystem(); - public String getId() { - return id; - } + /** + * Sets the system of the ObjectReference. + * + * @param system the system of the ObjectReference + */ + void setSystem(String system); - public void setId(String id) { - this.id = id; - } + /** + * Gets the systemInstance of the ObjectReference. + * + * @return the systemInstance + */ + String getSystemInstance(); - public String getCompany() { - return company; - } + /** + * Sets the system instance of the ObjectReference. + * + * @param systemInstance the system instance of the ObjectReference + */ + void setSystemInstance(String systemInstance); - public void setCompany(String company) { - this.company = company; - } + /** + * Gets the type of the ObjectReference. + * + * @return the type + */ + String getType(); - public String getSystem() { - return system; - } + /** + * Sets the type of the ObjectReference. + * + * @param type the type of the ObjectReference + */ + void setType(String type); - public void setSystem(String system) { - this.system = system; - } + /** + * Gets the value of the ObjectReference. + * + * @return the value + */ + String getValue(); - public String getSystemInstance() { - return systemInstance; - } + /** + * Sets the value of the ObjectReference. + * + * @param value the value of the ObjectReference + */ + void setValue(String value); - public void setSystemInstance(String systemInstance) { - this.systemInstance = systemInstance; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - public ObjectReference copy() { - return new ObjectReference(this); - } - - @Override - public int hashCode() { - return Objects.hash(id, company, system, systemInstance, type, value); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof ObjectReference)) { - return false; - } - ObjectReference other = (ObjectReference) obj; - return Objects.equals(id, other.id) - && Objects.equals(company, other.company) - && Objects.equals(system, other.system) - && Objects.equals(systemInstance, other.systemInstance) - && Objects.equals(type, other.type) - && Objects.equals(value, other.value); - } - - @Override - public String toString() { - return "ObjectReference [" - + "id=" - + this.id - + ", company=" - + this.company - + ", system=" - + this.system - + ", systemInstance=" - + this.systemInstance - + ", type=" - + this.type - + ", value=" - + this.value - + "]"; - } + /** + * Duplicates this ObjectReference without the id and taskId. + * + * @return a copy of this ObjectReference + */ + ObjectReference copy(); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/models/Task.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/models/Task.java index 7a4158931..195fae281 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/models/Task.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/models/Task.java @@ -19,10 +19,10 @@ public interface Task extends TaskSummary { String CALLBACK_STATE = "callbackState"; /** - * Sets the external Id. It can be used to correlate the task to a task in an external system. The - * external Id is enforced to be unique. An attempt to create a task with an existing external Id - * will be rejected. So, this Id can be used to enforce idempotency of task creation. The - * externalId can only be set before the task is inserted. Taskana rejects attempts to modify + * Sets the external Id. It can be used to correlate the Task to a Task in an external system. The + * external Id is enforced to be unique. An attempt to create a Task with an existing external Id + * will be rejected. So, this Id can be used to enforce idempotency of Task creation. The + * externalId can only be set before the Task is inserted. Taskana rejects attempts to modify * externalId. * * @param externalId the external Id @@ -30,7 +30,7 @@ public interface Task extends TaskSummary { void setExternalId(String externalId); /** - * Sets the time when the work on this task should be started. + * Sets the time when the work on this Task should be started. * * @param planned as exact {@link Instant} */ @@ -44,36 +44,36 @@ public interface Task extends TaskSummary { void setReceived(Instant received); /** - * Sets the time when the work on this task should be finished. + * Sets the time when the work on this Task should be finished. * * @param due as exact {@link Instant} */ void setDue(Instant due); /** - * Sets the name of the current task. + * Sets the name of the current Task. * - * @param name the name of the task + * @param name the name of the Task */ void setName(String name); /** - * Sets the description of the task. + * Sets the description of the Task. * - * @param description the description of the task + * @param description the description of the Task */ void setDescription(String description); /** - * Sets the Classification key that - together with the Domain from this task's work basket - - * selects the appropriate {@link Classification} for this task. + * Sets the Classification key that - together with the Domain from this Task's work basket - + * selects the appropriate {@link Classification} for this Task. * - * @param classificationKey the classification key for the task + * @param classificationKey the classification key for the Task */ void setClassificationKey(String classificationKey); /** - * Returns the key of the Workbasket where the task is stored in. + * Returns the key of the Workbasket where the Task is stored in. * * @return workbasketKey */ @@ -119,47 +119,59 @@ public interface Task extends TaskSummary { * Add an attachment.
* NULL will be ignored and an attachment with the same ID will be replaced by the newer one.
* - * @param attachment the {@link Attachment attachment} to be added to the task + * @param attachment the {@link Attachment attachment} to be added to the Task */ void addAttachment(Attachment attachment); /** - * Return the attachments for this task.
+ * Return the attachments for this Task.
* Do not use List.add()/addAll() for adding Elements, because it can cause redundant data. Use * addAttachment(). Clear() and remove() can be used, because it's a controllable change. * - * @return the {@link List list} of {@link Attachment attachments} for this task + * @return the {@link List list} of {@link Attachment attachments} for this Task */ List getAttachments(); /** * Sets the external business process id. * - * @param businessProcessId Sets the business process id the task belongs to. + * @param businessProcessId Sets the business process id the Task belongs to. */ void setBusinessProcessId(String businessProcessId); /** * Sets the parent business process id to group associated processes. * - * @param parentBusinessProcessId Sets the parent business process id the task belongs to + * @param parentBusinessProcessId Sets the parent business process id the Task belongs to */ void setParentBusinessProcessId(String parentBusinessProcessId); /** - * Sets the ownerId of this task. + * Sets the ownerId of this Task. * - * @param taskOwnerId the user id of the task's owner + * @param taskOwnerId the user id of the Task's owner */ void setOwner(String taskOwnerId); /** - * Sets the {@link ObjectReference primaryObjectReference} of the task. + * Sets the {@link ObjectReference primaryObjectReference} of the Task. * - * @param primaryObjRef to task main-subject + * @param primaryObjRef to Task main-subject */ void setPrimaryObjRef(ObjectReference primaryObjRef); + /** + * Initializes and sets the {@link ObjectReference primaryObjectReference} of the Task. + * + * @param company of the {@link ObjectReference primaryObjectReference} to be set + * @param system of the {@link ObjectReference primaryObjectReference} to be set + * @param systemInstance of the {@link ObjectReference primaryObjectReference} to be set + * @param type of the {@link ObjectReference primaryObjectReference} to be set + * @param value of the {@link ObjectReference primaryObjectReference} to be set + */ + void setPrimaryObjRef( + String company, String system, String systemInstance, String type, String value); + /** * Sets/Changing the custom note for this Task. * @@ -170,12 +182,12 @@ public interface Task extends TaskSummary { /** * Return a summary of the current Task. * - * @return the TaskSummary object for the current task + * @return the TaskSummary object for the current Task */ TaskSummary asSummary(); /** - * Removes an attachment of the current task locally, when the ID is represented and does return + * Removes an attachment of the current Task locally, when the ID is represented and does return * the removed attachment or null if there was no match.
* The changed Task need to be updated calling the {@link TaskService#updateTask(Task)}. * @@ -194,7 +206,7 @@ public interface Task extends TaskSummary { /** * Duplicates this Task without the internal and external id. All referenced {@link Attachment}s - * are copied as well. + * and {@link ObjectReference}s are copied as well. * * @return a copy of this Task */ diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/api/models/TaskSummary.java b/lib/taskana-core/src/main/java/pro/taskana/task/api/models/TaskSummary.java index c5960dbdf..05896622e 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/api/models/TaskSummary.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/api/models/TaskSummary.java @@ -5,6 +5,7 @@ import java.util.List; import pro.taskana.classification.api.models.ClassificationSummary; import pro.taskana.task.api.TaskCustomField; +import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.workbasket.api.models.WorkbasketSummary; @@ -15,21 +16,21 @@ import pro.taskana.workbasket.api.models.WorkbasketSummary; public interface TaskSummary { /** - * Gets the id of the task. + * Gets the id of the Task. * * @return taskId */ String getId(); /** - * Gets the external id of the task. + * Gets the external id of the Task. * * @return the external Id */ String getExternalId(); /** - * Gets the name of the task-creator. + * Gets the name of the creator of the Task. * * @return creator */ @@ -38,133 +39,176 @@ public interface TaskSummary { /** * Gets the time when the task was created. * - * @return the created Instant + * @return the created {@link Instant} */ Instant getCreated(); /** - * Gets the time when the task was claimed. + * Gets the time when the Task was claimed. * - * @return the claimed Instant + * @return the claimed {@link Instant} */ Instant getClaimed(); /** - * Gets the time when the task was completed. + * Gets the time when the Task was completed. * - * @return the completed Instant + * @return the completed {@link Instant} */ Instant getCompleted(); /** - * Gets the time when the task was last modified. + * Gets the time when the Task was last modified. * - * @return the last modified Instant + * @return the last modified {@link Instant} */ Instant getModified(); /** - * Gets the time when the task is planned to be executed. + * Gets the time when the Task is planned to be executed. * - * @return the planned Instant + * @return the planned {@link Instant} */ Instant getPlanned(); /** - * Gets the time when when the surrounding process was started. + * Gets the time when the surrounding process was started. * - * @return the received Instant + * @return the received {@link Instant} */ Instant getReceived(); /** - * Gets the time when the task is due. + * Gets the time when the Task is due. * - * @return the due Instant + * @return the due {@link Instant} */ Instant getDue(); /** - * Gets the name of the task. + * Gets the name of the Task. * - * @return the task's name + * @return the Task's name */ String getName(); /** - * Gets the note attached to the task. + * Gets the note attached to the Task. * - * @return the task's note + * @return the Task's note */ String getNote(); /** - * Gets the description of the task. + * Gets the description of the Task. * - * @return the task's description + * @return the Task's description */ String getDescription(); /** - * Gets the priority of the task. + * Gets the priority of the Task. * - * @return the task's priority + * @return the Task's priority */ int getPriority(); /** - * Gets the state of the task. + * Gets the state of the Task. * - * @return the task's state + * @return the Task's state */ TaskState getState(); /** - * Gets the classification summary of the task. + * Gets the {@link ClassificationSummary} of the Task. * - * @return the task's classificationSummary + * @return the Task's {@link ClassificationSummary} */ ClassificationSummary getClassificationSummary(); /** - * Gets the workbasket summary of the task. + * Gets the {@link WorkbasketSummary} of the Task. * - * @return the task's workbasketSummary + * @return the Task's {@link WorkbasketSummary} */ WorkbasketSummary getWorkbasketSummary(); /** - * Gets the attachment summaries of the task. + * Gets the {@link AttachmentSummary attachmentSummaries} of the Task. * - * @return the task's attachment summaries + * @return the Task's {@link AttachmentSummary attachmentSummaries} */ List getAttachmentSummaries(); /** - * Gets the domain of the task. + * Gets the secondary {@link ObjectReference}s of the Task. * - * @return the task's domain + * @return the Task's secondary {@link ObjectReference}s + */ + List getSecondaryObjectReferences(); + + /** + * Add an {@link ObjectReference} to the list of secondary {@link ObjectReference}s.
+ * NULL will be ignored and an ObjectReference with the same ID will be replaced by the newer one. + *
+ * + * @param objectReference the secondary {@link ObjectReference objectReference} to be added to the + * Task + */ + void addSecondaryObjectReference(ObjectReference objectReference); + + /** + * Add an {@link ObjectReference} to the list of secondary {@link ObjectReference}s.
+ * NULL will be ignored and an ObjectReference with the same ID will be replaced by the newer one. + *
+ * + * @param company of the {@link ObjectReference objectReference} to be added to the Task + * @param system of the {@link ObjectReference objectReference} to be added to the Task + * @param systemInstance of the {@link ObjectReference objectReference} to be added to the Task + * @param type of the {@link ObjectReference objectReference} to be added to the Task + * @param value of the {@link ObjectReference objectReference} to be added to the Task + */ + void addSecondaryObjectReference( + String company, String system, String systemInstance, String type, String value); + + /** + * Removes a secondary {@link ObjectReference} of the current Task locally, when the ID is + * represented and does return the removed {@link ObjectReference} or null if there was no match. + *
+ * The changed Task need to be updated calling the {@link TaskService#updateTask(Task)}. + * + * @param objectReferenceID ID of the {@link ObjectReference} which should be removed. + * @return the {@link ObjectReference} which will be removed after updating OR null if there was + * no matching {@link ObjectReference} + */ + ObjectReference removeSecondaryObjectReference(String objectReferenceID); + + /** + * Gets the domain of the Task. + * + * @return the Task's domain */ String getDomain(); /** - * Gets the businessProcessId of the task. + * Gets the businessProcessId of the Task. * - * @return the task's businessProcessId + * @return the Task's businessProcessId */ String getBusinessProcessId(); /** - * Gets the parentBusinessProcessId of the task. + * Gets the parentBusinessProcessId of the Task. * - * @return the task's parentBusinessProcessId + * @return the Task's parentBusinessProcessId */ String getParentBusinessProcessId(); /** - * Gets the owner of the task. + * Gets the owner of the Task. * - * @return the task's owner + * @return the Task's owner */ String getOwner(); @@ -176,28 +220,28 @@ public interface TaskSummary { String getOwnerLongName(); /** - * Gets the primary ObjectReference of the task. + * Gets the primary {@link ObjectReference} of the Task. * - * @return the task's primary ObjectReference + * @return the Task's primary {@link ObjectReference} */ ObjectReference getPrimaryObjRef(); /** - * Gets the isRead flag of the task. + * Gets the isRead flag of the Task. * - * @return the task's isRead flag + * @return the Task's isRead flag */ boolean isRead(); /** - * Gets the isTransferred flag of the task. + * Gets the isTransferred flag of the Task. * - * @return the task's isTransferred flag. + * @return the Task's isTransferred flag. */ boolean isTransferred(); /** - * Gets the custom attribute of the task. + * Gets the custom attribute of the Task. * * @param customField identifies which custom attribute is requested. * @return the value for the given customField diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/AttachmentHandler.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/AttachmentHandler.java index a966955bf..617a95fe8 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/AttachmentHandler.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/AttachmentHandler.java @@ -19,9 +19,9 @@ import pro.taskana.common.internal.util.IdGenerator; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; import pro.taskana.task.api.models.Attachment; import pro.taskana.task.api.models.AttachmentSummary; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; import pro.taskana.task.internal.models.AttachmentImpl; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskImpl; public class AttachmentHandler { @@ -183,7 +183,7 @@ public class AttachmentHandler { throw new InvalidArgumentException("ClassificationKey of Attachment must not be empty."); } - ObjectReference.validate(attachment.getObjectReference(), "ObjectReference", "Attachment"); + ObjectReferenceImpl.validate(attachment.getObjectReference(), "ObjectReference", "Attachment"); classification = classificationService diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/AttachmentMapper.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/AttachmentMapper.java index 241ed53b7..59754a43e 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/AttachmentMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/AttachmentMapper.java @@ -23,8 +23,8 @@ public interface AttachmentMapper { @Insert( "INSERT INTO ATTACHMENT (ID, TASK_ID, CREATED, MODIFIED, CLASSIFICATION_KEY, CLASSIFICATION_ID, REF_COMPANY, REF_SYSTEM, REF_INSTANCE, REF_TYPE, REF_VALUE, CHANNEL, RECEIVED, CUSTOM_ATTRIBUTES) " - + "VALUES (#{att.id}, #{att.taskId}, #{att.created}, #{att.modified}, #{att.classificationSummary.key}, #{att.classificationSummary.id}, #{att.objectReference.company}, #{att.objectReference.system}, #{att.objectReference.systemInstance}, " - + " #{att.objectReference.type}, #{att.objectReference.value}, #{att.channel}, #{att.received}, #{att.customAttributes,jdbcType=CLOB,javaType=java.util.Map,typeHandler=pro.taskana.common.internal.persistence.MapTypeHandler} )") + + "VALUES (#{att.id}, #{att.taskId}, #{att.created}, #{att.modified}, #{att.classificationSummary.key}, #{att.classificationSummary.id}, #{att.objectReferenceImpl.company}, #{att.objectReferenceImpl.system}, #{att.objectReferenceImpl.systemInstance}, " + + " #{att.objectReferenceImpl.type}, #{att.objectReferenceImpl.value}, #{att.channel}, #{att.received}, #{att.customAttributes,jdbcType=CLOB,javaType=java.util.Map,typeHandler=pro.taskana.common.internal.persistence.MapTypeHandler} )") void insert(@Param("att") AttachmentImpl att); @Select( @@ -39,11 +39,11 @@ public interface AttachmentMapper { @Result(property = "modified", column = "MODIFIED") @Result(property = "classificationSummaryImpl.key", column = "CLASSIFICATION_KEY") @Result(property = "classificationSummaryImpl.id", column = "CLASSIFICATION_ID") - @Result(property = "objectReference.company", column = "REF_COMPANY") - @Result(property = "objectReference.system", column = "REF_SYSTEM") - @Result(property = "objectReference.systemInstance", column = "REF_INSTANCE") - @Result(property = "objectReference.type", column = "REF_TYPE") - @Result(property = "objectReference.value", column = "REF_VALUE") + @Result(property = "objectReferenceImpl.company", column = "REF_COMPANY") + @Result(property = "objectReferenceImpl.system", column = "REF_SYSTEM") + @Result(property = "objectReferenceImpl.systemInstance", column = "REF_INSTANCE") + @Result(property = "objectReferenceImpl.type", column = "REF_TYPE") + @Result(property = "objectReferenceImpl.value", column = "REF_VALUE") @Result(property = "channel", column = "CHANNEL") @Result(property = "received", column = "RECEIVED") @Result( @@ -74,11 +74,11 @@ public interface AttachmentMapper { @Result(property = "modified", column = "MODIFIED") @Result(property = "classificationSummaryImpl.key", column = "CLASSIFICATION_KEY") @Result(property = "classificationSummaryImpl.id", column = "CLASSIFICATION_ID") - @Result(property = "objectReference.company", column = "REF_COMPANY") - @Result(property = "objectReference.system", column = "REF_SYSTEM") - @Result(property = "objectReference.systemInstance", column = "REF_INSTANCE") - @Result(property = "objectReference.type", column = "REF_TYPE") - @Result(property = "objectReference.value", column = "REF_VALUE") + @Result(property = "objectReferenceImpl.company", column = "REF_COMPANY") + @Result(property = "objectReferenceImpl.system", column = "REF_SYSTEM") + @Result(property = "objectReferenceImpl.systemInstance", column = "REF_INSTANCE") + @Result(property = "objectReferenceImpl.type", column = "REF_TYPE") + @Result(property = "objectReferenceImpl.value", column = "REF_VALUE") @Result(property = "channel", column = "CHANNEL") @Result(property = "received", column = "RECEIVED") List findAttachmentSummariesByTaskIds( @@ -93,8 +93,8 @@ public interface AttachmentMapper { @Update( "UPDATE ATTACHMENT SET TASK_ID = #{taskId}, CREATED = #{created}, MODIFIED = #{modified}," - + " CLASSIFICATION_KEY = #{classificationSummary.key}, CLASSIFICATION_ID = #{classificationSummary.id}, REF_COMPANY = #{objectReference.company}, REF_SYSTEM = #{objectReference.system}," - + " REF_INSTANCE = #{objectReference.systemInstance}, REF_TYPE = #{objectReference.type}, REF_VALUE = #{objectReference.value}," + + " CLASSIFICATION_KEY = #{classificationSummary.key}, CLASSIFICATION_ID = #{classificationSummary.id}, REF_COMPANY = #{objectReferenceImpl.company}, REF_SYSTEM = #{objectReferenceImpl.system}," + + " REF_INSTANCE = #{objectReferenceImpl.systemInstance}, REF_TYPE = #{objectReferenceImpl.type}, REF_VALUE = #{objectReferenceImpl.value}," + " CHANNEL = #{channel}, RECEIVED = #{received}, CUSTOM_ATTRIBUTES = #{customAttributes,jdbcType=CLOB,javaType=java.util.Map,typeHandler=pro.taskana.common.internal.persistence.MapTypeHandler}" + " WHERE ID = #{id}") void update(AttachmentImpl attachment); diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/ObjectReferenceHandler.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/ObjectReferenceHandler.java new file mode 100644 index 000000000..ab031e363 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/ObjectReferenceHandler.java @@ -0,0 +1,164 @@ +package pro.taskana.task.internal; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.apache.ibatis.exceptions.PersistenceException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import pro.taskana.common.api.exceptions.InvalidArgumentException; +import pro.taskana.common.internal.util.IdGenerator; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; +import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.models.ObjectReferenceImpl; +import pro.taskana.task.internal.models.TaskImpl; + +/** Handles all operations on secondary {@link ObjectReference}s. */ +public class ObjectReferenceHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(ObjectReferenceHandler.class); + private final ObjectReferenceMapper objectReferenceMapper; + + ObjectReferenceHandler(ObjectReferenceMapper objectReferenceMapper) { + this.objectReferenceMapper = objectReferenceMapper; + } + + void insertNewSecondaryObjectReferencesOnTaskCreation(TaskImpl task) + throws ObjectReferencePersistenceException, InvalidArgumentException { + List objectReferences = task.getSecondaryObjectReferences(); + + if (objectReferences != null) { + for (ObjectReference objectReference : objectReferences) { + ObjectReferenceImpl objectReferenceImpl = (ObjectReferenceImpl) objectReference; + initObjectReference(objectReferenceImpl, task); + ObjectReferenceImpl.validate(objectReferenceImpl, "ObjectReference", "Task"); + try { + objectReferenceMapper.insert(objectReferenceImpl); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "TaskService.createTask() for TaskId={} INSERTED an object reference={}.", + task.getId(), + objectReference); + } + } catch (PersistenceException e) { + throw new ObjectReferencePersistenceException(objectReference.getId(), task.getId(), e); + } + } + } + } + + void insertAndDeleteObjectReferencesOnTaskUpdate(TaskImpl newTaskImpl, TaskImpl oldTaskImpl) + throws ObjectReferencePersistenceException, InvalidArgumentException { + List newObjectReferences = + newTaskImpl.getSecondaryObjectReferences().stream() + .filter(Objects::nonNull) + .collect(Collectors.toList()); + newTaskImpl.setSecondaryObjectReferences(newObjectReferences); + + for (ObjectReference objectReference : newObjectReferences) { + ObjectReferenceImpl.validate(objectReference, "Object Reference", "Task"); + initObjectReference((ObjectReferenceImpl) objectReference, newTaskImpl); + } + + deleteRemovedObjectReferencesOnTaskUpdate(newTaskImpl, oldTaskImpl); + insertNewObjectReferencesOnTaskUpdate(newTaskImpl, oldTaskImpl); + updateModifiedObjectReferencesOnTaskUpdate(newTaskImpl, oldTaskImpl); + } + + private void insertNewObjectReferencesOnTaskUpdate(TaskImpl newTaskImpl, TaskImpl oldTaskImpl) + throws ObjectReferencePersistenceException { + Set oldObjectReferencesIds = + oldTaskImpl.getSecondaryObjectReferences().stream() + .map(ObjectReference::getId) + .collect(Collectors.toSet()); + + List newObjectReferences = + newTaskImpl.getSecondaryObjectReferences().stream() + .filter(o -> !oldObjectReferencesIds.contains(o.getId())) + .collect(Collectors.toList()); + + for (ObjectReference objectReference : newObjectReferences) { + insertNewObjectReferenceOnTaskUpdate(newTaskImpl, objectReference); + } + } + + private void updateModifiedObjectReferencesOnTaskUpdate( + TaskImpl newTaskImpl, TaskImpl oldTaskImpl) { + List newObjectReferences = newTaskImpl.getSecondaryObjectReferences(); + List oldObjectReferences = oldTaskImpl.getSecondaryObjectReferences(); + if (newObjectReferences != null + && !newObjectReferences.isEmpty() + && oldObjectReferences != null + && !oldObjectReferences.isEmpty()) { + final Map oldObjectReferencesMap = + oldObjectReferences.stream() + .collect(Collectors.toMap(ObjectReference::getId, Function.identity())); + newObjectReferences.forEach( + o -> { + if (oldObjectReferencesMap.containsKey(o.getId()) + && !o.equals(oldObjectReferencesMap.get(o.getId()))) { + objectReferenceMapper.update((ObjectReferenceImpl) o); + } + }); + } + } + + private void deleteRemovedObjectReferencesOnTaskUpdate( + TaskImpl newTaskImpl, TaskImpl oldTaskImpl) { + + final List newObjectReferences = newTaskImpl.getSecondaryObjectReferences(); + List newObjectReferencesIds = new ArrayList<>(); + if (newObjectReferences != null && !newObjectReferences.isEmpty()) { + newObjectReferencesIds = + newObjectReferences.stream().map(ObjectReference::getId).collect(Collectors.toList()); + } + List oldObjectReferences = oldTaskImpl.getSecondaryObjectReferences(); + if (oldObjectReferences != null && !oldObjectReferences.isEmpty()) { + final List newObjRefIds = newObjectReferencesIds; + oldObjectReferences.forEach( + o -> { + if (!newObjRefIds.contains(o.getId())) { + objectReferenceMapper.delete(o.getId()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "TaskService.updateTask() for TaskId={} DELETED an ObjectReference={}.", + newTaskImpl.getId(), + o); + } + } + }); + } + } + + private void insertNewObjectReferenceOnTaskUpdate( + TaskImpl newTaskImpl, ObjectReference objectReference) + throws ObjectReferencePersistenceException { + ObjectReferenceImpl objectReferenceImpl = (ObjectReferenceImpl) objectReference; + try { + objectReferenceMapper.insert(objectReferenceImpl); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "TaskService.updateTask() for TaskId={} INSERTED an ObjectReference={}.", + newTaskImpl.getId(), + objectReferenceImpl); + } + } catch (PersistenceException e) { + throw new ObjectReferencePersistenceException( + objectReferenceImpl.getId(), newTaskImpl.getId(), e); + } + } + + private void initObjectReference(ObjectReferenceImpl objectReference, Task newTask) { + if (objectReference.getTaskId() == null) { + objectReference.setTaskId(newTask.getId()); + } + if (objectReference.getId() == null) { + objectReference.setId(IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_OBJECT_REFERENCE)); + } + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/ObjectReferenceMapper.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/ObjectReferenceMapper.java index 4821a6a70..0c3b4892a 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/ObjectReferenceMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/ObjectReferenceMapper.java @@ -1,5 +1,6 @@ package pro.taskana.task.internal; +import java.util.Collection; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; @@ -9,7 +10,7 @@ import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.SelectProvider; import org.apache.ibatis.annotations.Update; -import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.internal.models.ObjectReferenceImpl; /** This class is the mybatis mapping of ObjectReference. */ @SuppressWarnings({"checkstyle:LineLength", "checkstyle:Indentation"}) @@ -27,7 +28,47 @@ public interface ObjectReferenceMapper { @Result(property = "systemInstance", column = "SYSTEM_INSTANCE") @Result(property = "type", column = "TYPE") @Result(property = "value", column = "VALUE") - ObjectReference findById(@Param("id") String id); + ObjectReferenceImpl findById(@Param("id") String id); + + @Select( + "") + @Result(property = "id", column = "ID") + @Result(property = "taskId", column = "TASK_ID") + @Result(property = "company", column = "COMPANY") + @Result(property = "system", column = "SYSTEM") + @Result(property = "systemInstance", column = "SYSTEM_INSTANCE") + @Result(property = "type", column = "TYPE") + @Result(property = "value", column = "VALUE") + List findObjectReferencesByTaskId(@Param("taskId") String taskId); + + @Select( + "") + @Result(property = "id", column = "ID") + @Result(property = "taskId", column = "TASK_ID") + @Result(property = "company", column = "COMPANY") + @Result(property = "system", column = "SYSTEM") + @Result(property = "systemInstance", column = "SYSTEM_INSTANCE") + @Result(property = "type", column = "TYPE") + @Result(property = "value", column = "VALUE") + List findObjectReferencesByTaskIds( + @Param("taskIds") Collection taskIds); @Select( "") + void deleteMultipleByTaskIds(@Param("taskIds") List taskIds); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskMapper.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskMapper.java index 6aa009202..2adf24283 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskMapper.java @@ -56,11 +56,11 @@ public interface TaskMapper { @Result(property = "businessProcessId", column = "BUSINESS_PROCESS_ID") @Result(property = "parentBusinessProcessId", column = "PARENT_BUSINESS_PROCESS_ID") @Result(property = "owner", column = "OWNER") - @Result(property = "primaryObjRef.company", column = "POR_COMPANY") - @Result(property = "primaryObjRef.system", column = "POR_SYSTEM") - @Result(property = "primaryObjRef.systemInstance", column = "POR_INSTANCE") - @Result(property = "primaryObjRef.type", column = "POR_TYPE") - @Result(property = "primaryObjRef.value", column = "POR_VALUE") + @Result(property = "primaryObjRefImpl.company", column = "POR_COMPANY") + @Result(property = "primaryObjRefImpl.system", column = "POR_SYSTEM") + @Result(property = "primaryObjRefImpl.systemInstance", column = "POR_INSTANCE") + @Result(property = "primaryObjRefImpl.type", column = "POR_TYPE") + @Result(property = "primaryObjRefImpl.value", column = "POR_VALUE") @Result(property = "isRead", column = "IS_READ") @Result(property = "isTransferred", column = "IS_TRANSFERRED") @Result( diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryImpl.java index 097131bde..a61007924 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryImpl.java @@ -56,6 +56,7 @@ public class TaskQueryImpl implements TaskQuery { private boolean selectAndClaim; private boolean useDistinctKeyword = false; private boolean joinWithAttachments = false; + private boolean joinWithSecondaryObjectReferences = false; private boolean joinWithClassifications = false; private boolean joinWithAttachmentClassifications = false; private boolean joinWithWorkbaskets = false; @@ -255,6 +256,29 @@ public class TaskQueryImpl implements TaskQuery { private TimeInterval[] attachmentReceivedWithin; private TimeInterval[] attachmentReceivedNotWithin; // endregion + // region secondaryObjectReferences + private ObjectReference[] secondaryObjectReferences; + // endregion + // region secondaryObjectReferenceCompany + private String[] sorCompanyIn; + private String[] sorCompanyLike; + // endregion + // region secondaryObjectReferenceValue + private String[] sorValueIn; + private String[] sorValueLike; + // endregion + // region secondaryObjectReferenceSystem + private String[] sorSystemIn; + private String[] sorSystemLike; + // endregion + // region secondaryObjectReferenceSystemInstance + private String[] sorSystemInstanceIn; + private String[] sorSystemInstanceLike; + // endregion + // region secondaryObjectReferenceType + private String[] sorTypeIn; + private String[] sorTypeLike; + // endregion // region customAttributes private String[] custom1In; private boolean custom1InContainsNull; @@ -1386,6 +1410,88 @@ public class TaskQueryImpl implements TaskQuery { public String[] getOwnerLongNameNotLike() { return ownerLongNameNotLike; } + + // region secondaryObjectReference + + @Override + public TaskQuery secondaryObjectReferenceIn(ObjectReference... objectReferences) { + this.joinWithSecondaryObjectReferences = true; + this.secondaryObjectReferences = objectReferences; + return this; + } + + // endregion + // region secondaryObjectReferenceCompany + public TaskQuery sorCompanyIn(String... companyIn) { + joinWithSecondaryObjectReferences = true; + sorCompanyIn = companyIn; + return this; + } + + public TaskQuery sorCompanyLike(String... companyLike) { + joinWithSecondaryObjectReferences = true; + sorCompanyLike = toUpperCopy(companyLike); + return this; + } + + // endregion + // region secondaryObjectReferenceSystem + public TaskQuery sorSystemIn(String... systemIn) { + joinWithSecondaryObjectReferences = true; + sorSystemIn = systemIn; + return this; + } + + public TaskQuery sorSystemLike(String... systemLike) { + joinWithSecondaryObjectReferences = true; + sorSystemLike = toUpperCopy(systemLike); + return this; + } + + // endregion + // region secondaryObjectReferenceSystemInstance + public TaskQuery sorSystemInstanceIn(String... systemInstanceIn) { + joinWithSecondaryObjectReferences = true; + sorSystemInstanceIn = systemInstanceIn; + return this; + } + + public TaskQuery sorSystemInstanceLike(String... systemInstanceLike) { + joinWithSecondaryObjectReferences = true; + sorSystemInstanceLike = toUpperCopy(systemInstanceLike); + return this; + } + + // endregion + // region secondaryObjectReferenceType + public TaskQuery sorTypeIn(String... typeIn) { + joinWithSecondaryObjectReferences = true; + sorTypeIn = typeIn; + return this; + } + + public TaskQuery sorTypeLike(String... typeLike) { + joinWithSecondaryObjectReferences = true; + sorTypeLike = toUpperCopy(typeLike); + return this; + } + + // endregion + // region secondaryObjectReferenceValue + @Override + public TaskQuery sorValueIn(String... valueIn) { + joinWithSecondaryObjectReferences = true; + sorValueIn = valueIn; + return this; + } + + public TaskQuery sorValueLike(String... valueLike) { + joinWithSecondaryObjectReferences = true; + sorValueLike = toUpperCopy(valueLike); + return this; + } + + // endregion // region customAttributes @Override @@ -1779,6 +1885,7 @@ public class TaskQueryImpl implements TaskQuery { this.wildcardSearchValueLike = wildcardSearchValue.toUpperCase(); return this; } + // endregion @Override public TaskQuery wildcardSearchFieldsIn(WildcardSearchField... wildcardSearchFields) { @@ -1886,6 +1993,10 @@ public class TaskQueryImpl implements TaskQuery { joinWithAttachments = true; } + if (columnName.isObjectReferenceColumn()) { + joinWithSecondaryObjectReferences = true; + } + if (columnName == TaskQueryColumnName.OWNER_LONG_NAME) { joinWithUserInfo = true; } @@ -1998,7 +2109,7 @@ public class TaskQueryImpl implements TaskQuery { joinWithAttachments = true; joinWithAttachmentClassifications = true; } - if (joinWithAttachments || joinWithClassifications) { + if (joinWithAttachments || joinWithClassifications || joinWithSecondaryObjectReferences) { useDistinctKeyword = true; } } @@ -2110,6 +2221,8 @@ public class TaskQueryImpl implements TaskQuery { + joinWithAttachmentClassifications + ", joinWithWorkbaskets=" + joinWithWorkbaskets + + ", joinWithSecondaryObjectReferences=" + + joinWithSecondaryObjectReferences + ", addAttachmentColumnsToSelectClauseForOrdering=" + addAttachmentColumnsToSelectClauseForOrdering + ", addClassificationNameToSelectClauseForOrdering=" @@ -2340,6 +2453,28 @@ public class TaskQueryImpl implements TaskQuery { + Arrays.toString(attachmentReceivedWithin) + ", attachmentReceivedNotWithin=" + Arrays.toString(attachmentReceivedNotWithin) + + ", secondaryObjectReferences=" + + Arrays.toString(secondaryObjectReferences) + + ", sorCompanyIn=" + + Arrays.toString(sorCompanyIn) + + ", sorCompanyLike=" + + Arrays.toString(sorCompanyLike) + + ", sorSystemIn=" + + Arrays.toString(sorSystemIn) + + ", sorSystemNotIn=" + + Arrays.toString(sorSystemLike) + + ", sorSystemNotLike=" + + Arrays.toString(sorSystemInstanceIn) + + ", sorSystemInstanceLike=" + + Arrays.toString(sorSystemInstanceLike) + + ", sorTypeIn=" + + Arrays.toString(sorTypeIn) + + ", sorTypeLike=" + + Arrays.toString(sorTypeLike) + + ", sorValueIn=" + + Arrays.toString(sorValueIn) + + ", sorValueLike=" + + Arrays.toString(sorValueLike) + ", custom1In=" + Arrays.toString(custom1In) + ", custom1NotIn=" diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryMapper.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryMapper.java index ff40bff7b..9f3544bb4 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQueryMapper.java @@ -36,11 +36,11 @@ public interface TaskQueryMapper { @Result(property = "parentBusinessProcessId", column = "PARENT_BUSINESS_PROCESS_ID") @Result(property = "owner", column = "OWNER") @Result(property = "ownerLongName", column = "LONG_NAME") - @Result(property = "primaryObjRef.company", column = "POR_COMPANY") - @Result(property = "primaryObjRef.system", column = "POR_SYSTEM") - @Result(property = "primaryObjRef.systemInstance", column = "POR_INSTANCE") - @Result(property = "primaryObjRef.type", column = "POR_TYPE") - @Result(property = "primaryObjRef.value", column = "POR_VALUE") + @Result(property = "primaryObjRefImpl.company", column = "POR_COMPANY") + @Result(property = "primaryObjRefImpl.system", column = "POR_SYSTEM") + @Result(property = "primaryObjRefImpl.systemInstance", column = "POR_INSTANCE") + @Result(property = "primaryObjRefImpl.type", column = "POR_TYPE") + @Result(property = "primaryObjRefImpl.value", column = "POR_VALUE") @Result(property = "isRead", column = "IS_READ") @Result(property = "isTransferred", column = "IS_TRANSFERRED") @Result(property = "custom1", column = "CUSTOM_1") @@ -88,11 +88,11 @@ public interface TaskQueryMapper { @Result(property = "parentBusinessProcessId", column = "PARENT_BUSINESS_PROCESS_ID") @Result(property = "owner", column = "OWNER") @Result(property = "ownerLongName", column = "ULONG_NAME") - @Result(property = "primaryObjRef.company", column = "POR_COMPANY") - @Result(property = "primaryObjRef.system", column = "POR_SYSTEM") - @Result(property = "primaryObjRef.systemInstance", column = "POR_INSTANCE") - @Result(property = "primaryObjRef.type", column = "POR_TYPE") - @Result(property = "primaryObjRef.value", column = "POR_VALUE") + @Result(property = "primaryObjRefImpl.company", column = "POR_COMPANY") + @Result(property = "primaryObjRefImpl.system", column = "POR_SYSTEM") + @Result(property = "primaryObjRefImpl.systemInstance", column = "POR_INSTANCE") + @Result(property = "primaryObjRefImpl.type", column = "POR_TYPE") + @Result(property = "primaryObjRefImpl.value", column = "POR_VALUE") @Result(property = "isRead", column = "IS_READ") @Result(property = "isTransferred", column = "IS_TRANSFERRED") @Result(property = "custom1", column = "CUSTOM_1") diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQuerySqlProvider.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQuerySqlProvider.java index 7ca37dc87..7dd215c04 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQuerySqlProvider.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskQuerySqlProvider.java @@ -37,6 +37,9 @@ public class TaskQuerySqlProvider { + "" + "LEFT JOIN ATTACHMENT AS a ON t.ID = a.TASK_ID " + "" + + "" + + "LEFT JOIN OBJECT_REFERENCE AS o ON t.ID = o.TASK_ID " + + "" + "" + "LEFT JOIN CLASSIFICATION AS c ON t.CLASSIFICATION_ID = c.ID " + "" @@ -83,6 +86,9 @@ public class TaskQuerySqlProvider { + "" + "LEFT JOIN ATTACHMENT a ON t.ID = a.TASK_ID " + "" + + "" + + "LEFT JOIN OBJECT_REFERENCE o ON t.ID = o.TASK_ID " + + "" + "" + "LEFT JOIN CLASSIFICATION AS c ON t.CLASSIFICATION_ID = c.ID " + "" @@ -135,6 +141,9 @@ public class TaskQuerySqlProvider { + "" + "LEFT JOIN ATTACHMENT AS a ON t.ID = a.TASK_ID " + "" + + "" + + "LEFT JOIN OBJECT_REFERENCE AS o ON t.ID = o.TASK_ID " + + "" + "" + "LEFT JOIN CLASSIFICATION AS c ON t.CLASSIFICATION_ID = c.ID " + "" @@ -166,6 +175,9 @@ public class TaskQuerySqlProvider { + "" + "LEFT JOIN CLASSIFICATION AS ac ON a.CLASSIFICATION_ID = ac.ID " + "" + + "" + + "LEFT JOIN OBJECT_REFERENCE AS o ON t.ID = o.TASK_ID " + + "" + "" + "LEFT JOIN USER_INFO AS u ON t.owner = u.USER_ID " + "" @@ -199,6 +211,9 @@ public class TaskQuerySqlProvider { + "" + "LEFT JOIN CLASSIFICATION AS ac ON a.CLASSIFICATION_ID = ac.ID " + "" + + "" + + "LEFT JOIN OBJECT_REFERENCE AS o ON t.ID = o.TASK_ID " + + "" + "" + "LEFT JOIN USER_INFO AS u ON t.owner = u.USER_ID " + "" @@ -310,6 +325,30 @@ public class TaskQuerySqlProvider { + ""; } + private static String commonTaskSecondaryObjectReferencesWhereStatement() { + return "" + + "AND ( " + + "o.COMPANY = #{item.company} " + + " " + + "AND " + + "o.SYSTEM = #{item.system} " + + " " + + "AND " + + "o.SYSTEM_INSTANCE = #{item.systemInstance} " + + " " + + "" + + "AND " + + "o.TYPE = #{item.type} " + + " " + + "" + + "AND " + + "o.VALUE = #{item.value} " + + "" + + ")" + + ""; + } + private static void commonWhereClauses(String filter, String channel, StringBuilder sb) { whereIn(filter + "In", channel, sb); whereNotIn(filter + "NotIn", channel, sb); @@ -337,6 +376,17 @@ public class TaskQuerySqlProvider { commonWhereClauses("porType", "t.POR_TYPE", sb); commonWhereClauses("porValue", "t.POR_VALUE", sb); + whereIn("sorCompanyIn", "o.COMPANY", sb); + whereLike("sorCompanyLike", "o.COMPANY", sb); + whereIn("sorSystemIn", "o.SYSTEM", sb); + whereLike("sorSystemLike", "o.SYSTEM", sb); + whereIn("sorSystemInstanceIn", "o.SYSTEM_INSTANCE", sb); + whereLike("sorSystemInstanceLike", "o.SYSTEM_INSTANCE", sb); + whereIn("sorTypeIn", "o.TYPE", sb); + whereLike("sorTypeLike", "o.TYPE", sb); + whereIn("sorValueIn", "o.VALUE", sb); + whereLike("sorValueLike", "o.VALUE", sb); + whereIn("attachmentClassificationIdIn", "a.CLASSIFICATION_ID", sb); whereNotIn("attachmentClassificationIdNotIn", "a.CLASSIFICATION_ID", sb); whereIn("callbackStateIn", "t.CALLBACK_STATE", sb); @@ -399,6 +449,7 @@ public class TaskQuerySqlProvider { + ")" + " "); sb.append(commonTaskObjectReferenceWhereStatement()); + sb.append(commonTaskSecondaryObjectReferencesWhereStatement()); return sb; } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java index df3b2c417..bce70c49c 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/TaskServiceImpl.java @@ -61,6 +61,7 @@ import pro.taskana.task.api.exceptions.InvalidCallbackStateException; import pro.taskana.task.api.exceptions.InvalidOwnerException; import pro.taskana.task.api.exceptions.InvalidStateException; import pro.taskana.task.api.exceptions.InvalidTaskStateException; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskCommentNotFoundException; import pro.taskana.task.api.exceptions.TaskNotFoundException; @@ -74,6 +75,7 @@ import pro.taskana.task.internal.ServiceLevelHandler.BulkLog; import pro.taskana.task.internal.models.AttachmentImpl; import pro.taskana.task.internal.models.AttachmentSummaryImpl; import pro.taskana.task.internal.models.MinimalTaskSummary; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskImpl; import pro.taskana.task.internal.models.TaskSummaryImpl; import pro.taskana.user.api.models.User; @@ -102,6 +104,8 @@ public class TaskServiceImpl implements TaskService { private final ServiceLevelHandler serviceLevelHandler; private final AttachmentHandler attachmentHandler; private final AttachmentMapper attachmentMapper; + private final ObjectReferenceMapper objectReferenceMapper; + private final ObjectReferenceHandler objectReferenceHandler; private final UserMapper userMapper; private final HistoryEventManager historyEventManager; private final CreateTaskPreprocessorManager createTaskPreprocessorManager; @@ -112,11 +116,13 @@ public class TaskServiceImpl implements TaskService { TaskMapper taskMapper, TaskCommentMapper taskCommentMapper, AttachmentMapper attachmentMapper, + ObjectReferenceMapper objectReferenceMapper, UserMapper userMapper) { this.taskanaEngine = taskanaEngine; this.taskMapper = taskMapper; this.workbasketService = taskanaEngine.getEngine().getWorkbasketService(); this.attachmentMapper = attachmentMapper; + this.objectReferenceMapper = objectReferenceMapper; this.userMapper = userMapper; this.classificationService = taskanaEngine.getEngine().getClassificationService(); this.historyEventManager = taskanaEngine.getHistoryEventManager(); @@ -128,6 +134,7 @@ public class TaskServiceImpl implements TaskService { this.serviceLevelHandler = new ServiceLevelHandler(taskanaEngine, taskMapper, attachmentMapper, this); this.attachmentHandler = new AttachmentHandler(attachmentMapper, classificationService); + this.objectReferenceHandler = new ObjectReferenceHandler(objectReferenceMapper); } @Override @@ -175,7 +182,8 @@ public class TaskServiceImpl implements TaskService { @Override public Task createTask(Task taskToCreate) throws NotAuthorizedException, WorkbasketNotFoundException, ClassificationNotFoundException, - TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException { + TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, + ObjectReferencePersistenceException { if (createTaskPreprocessorManager.isEnabled()) { taskToCreate = createTaskPreprocessorManager.processTaskBeforeCreation(taskToCreate); @@ -230,7 +238,7 @@ public class TaskServiceImpl implements TaskService { Classification classification = this.classificationService.getClassification(classificationKey, workbasket.getDomain()); task.setClassificationSummary(classification.asSummary()); - ObjectReference.validate(task.getPrimaryObjRef(), "primary ObjectReference", "Task"); + ObjectReferenceImpl.validate(task.getPrimaryObjRef(), "primary ObjectReference", "Task"); standardSettingsOnTaskCreation(task, classification); setCallbackStateOnTaskCreation(task); priorityServiceManager.calculatePriorityOfTask(task).ifPresent(task::setPriority); @@ -313,12 +321,16 @@ public class TaskServiceImpl implements TaskService { if (attachmentImpls == null) { attachmentImpls = new ArrayList<>(); } - + List secondaryObjectReferences = + objectReferenceMapper.findObjectReferencesByTaskId(resultTask.getId()); + if (secondaryObjectReferences == null) { + secondaryObjectReferences = new ArrayList<>(); + } Map classificationSummariesById = findClassificationForTaskImplAndAttachments(resultTask, attachmentImpls); addClassificationSummariesToAttachments(attachmentImpls, classificationSummariesById); resultTask.setAttachments(new ArrayList<>(attachmentImpls)); - + resultTask.setSecondaryObjectReferences(new ArrayList<>(secondaryObjectReferences)); String classificationId = resultTask.getClassificationSummary().getId(); ClassificationSummary classification = classificationSummariesById.get(classificationId); if (classification == null) { @@ -423,10 +435,22 @@ public class TaskServiceImpl implements TaskService { return new AttachmentImpl(); } + @Override + public ObjectReference newObjectReference() { + return new ObjectReferenceImpl(); + } + + @Override + public ObjectReference newObjectReference( + String company, String system, String systemInstance, String type, String value) { + return new ObjectReferenceImpl(company, system, systemInstance, type, value); + } + @Override public Task updateTask(Task task) throws InvalidArgumentException, TaskNotFoundException, ConcurrencyException, - NotAuthorizedException, AttachmentPersistenceException, InvalidStateException, + NotAuthorizedException, AttachmentPersistenceException, + ObjectReferencePersistenceException, InvalidStateException, ClassificationNotFoundException { String userId = taskanaEngine.getEngine().getCurrentUserContext().getUserid(); TaskImpl newTaskImpl = (TaskImpl) task; @@ -437,7 +461,9 @@ public class TaskServiceImpl implements TaskService { checkConcurrencyAndSetModified(newTaskImpl, oldTaskImpl); attachmentHandler.insertAndDeleteAttachmentsOnTaskUpdate(newTaskImpl, oldTaskImpl); - ObjectReference.validate(newTaskImpl.getPrimaryObjRef(), "primary ObjectReference", "Task"); + objectReferenceHandler.insertAndDeleteObjectReferencesOnTaskUpdate(newTaskImpl, oldTaskImpl); + ObjectReferenceImpl.validate( + newTaskImpl.getPrimaryObjRef(), "primary ObjectReference", "Task"); standardUpdateActions(oldTaskImpl, newTaskImpl); @@ -555,6 +581,7 @@ public class TaskServiceImpl implements TaskService { if (!taskIds.isEmpty()) { attachmentMapper.deleteMultipleByTaskIds(taskIds); + objectReferenceMapper.deleteMultipleByTaskIds(taskIds); taskMapper.deleteMultiple(taskIds); if (taskanaEngine.getEngine().isHistoryEnabled() @@ -588,7 +615,7 @@ public class TaskServiceImpl implements TaskService { ObjectReference selectionCriteria, Map customFieldsToUpdate) throws InvalidArgumentException { - ObjectReference.validate(selectionCriteria, "ObjectReference", "updateTasks call"); + ObjectReferenceImpl.validate(selectionCriteria, "ObjectReference", "updateTasks call"); validateCustomFields(customFieldsToUpdate); TaskCustomPropertySelector fieldSelector = new TaskCustomPropertySelector(); TaskImpl updated = initUpdatedTask(customFieldsToUpdate, fieldSelector); @@ -952,7 +979,7 @@ public class TaskServiceImpl implements TaskService { // splitting Augmentation into steps of maximal 32000 tasks // reason: DB2 has a maximum for parameters in a query return CollectionUtil.partitionBasedOnSize(taskSummaries, 32000).stream() - .map(this::augmentTaskSummariesByContainedSummariesWithoutPartitioning) + .map(this::appendComplexAttributesToTaskSummariesWithoutPartitioning) .flatMap(Collection::stream) .collect(Collectors.toList()); } @@ -975,7 +1002,7 @@ public class TaskServiceImpl implements TaskService { return Pair.of(filteredTasks, bulkLog); } - private List augmentTaskSummariesByContainedSummariesWithoutPartitioning( + private List appendComplexAttributesToTaskSummariesWithoutPartitioning( List taskSummaries) { Set taskIds = taskSummaries.stream().map(TaskSummaryImpl::getId).collect(Collectors.toSet()); @@ -995,12 +1022,15 @@ public class TaskServiceImpl implements TaskService { attachmentMapper.findAttachmentSummariesByTaskIds(taskIds); Map classificationSummariesById = findClassificationsForTasksAndAttachments(taskSummaries, attachmentSummaries); - Map workbasketSummariesById = findWorkbasketsForTasks(taskSummaries); - addClassificationSummariesToAttachments(attachmentSummaries, classificationSummariesById); addClassificationSummariesToTaskSummaries(taskSummaries, classificationSummariesById); - addWorkbasketSummariesToTaskSummaries(taskSummaries, workbasketSummariesById); addAttachmentSummariesToTaskSummaries(taskSummaries, attachmentSummaries); + Map workbasketSummariesById = findWorkbasketsForTasks(taskSummaries); + List objectReferences = + objectReferenceMapper.findObjectReferencesByTaskIds(taskIds); + + addWorkbasketSummariesToTaskSummaries(taskSummaries, workbasketSummariesById); + addObjectReferencesToTaskSummaries(taskSummaries, objectReferences); return taskSummaries; } @@ -1306,6 +1336,7 @@ public class TaskServiceImpl implements TaskService { } attachmentMapper.deleteMultipleByTaskIds(Collections.singletonList(taskId)); + objectReferenceMapper.deleteMultipleByTaskIds(Collections.singletonList(taskId)); taskMapper.delete(taskId); if (taskanaEngine.getEngine().isHistoryEnabled() @@ -1443,7 +1474,7 @@ public class TaskServiceImpl implements TaskService { private void standardSettingsOnTaskCreation(TaskImpl task, Classification classification) throws InvalidArgumentException, ClassificationNotFoundException, - AttachmentPersistenceException { + AttachmentPersistenceException, ObjectReferencePersistenceException { final Instant now = Instant.now(); task.setId(IdGenerator.generateWithPrefix(IdGenerator.ID_PREFIX_TASK)); if (task.getExternalId() == null) { @@ -1480,6 +1511,7 @@ public class TaskServiceImpl implements TaskService { setDefaultTaskReceivedDateFromAttachments(task); attachmentHandler.insertNewAttachmentsOnTaskCreation(task); + objectReferenceHandler.insertNewSecondaryObjectReferencesOnTaskCreation(task); // This has to be called after the AttachmentHandler because the AttachmentHandler fetches // the Classifications of the Attachments. // This is necessary to guarantee that the following calculation is correct. @@ -1706,6 +1738,32 @@ public class TaskServiceImpl implements TaskService { } } + private void addObjectReferencesToTaskSummaries( + List taskSummaries, List objectReferences) { + if (taskSummaries == null || taskSummaries.isEmpty()) { + return; + } + + Map taskSummariesById = + taskSummaries.stream() + .collect( + Collectors.toMap( + TaskSummary::getId, + Function.identity(), + // The TaskQuery#list function + // returns the same task multiple times when that task has more than one + // object reference...Therefore, this MergeFunction is necessary. + (a, b) -> b)); + + for (ObjectReferenceImpl objectReference : objectReferences) { + String taskId = objectReference.getTaskId(); + TaskSummaryImpl taskSummary = taskSummariesById.get(taskId); + if (taskSummary != null) { + taskSummary.addSecondaryObjectReference(objectReference); + } + } + } + private TaskImpl initUpdatedTask( Map customFieldsToUpdate, TaskCustomPropertySelector fieldSelector) { diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/builder/ObjectReferenceBuilder.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/builder/ObjectReferenceBuilder.java index 28b055563..71c2b11ed 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/builder/ObjectReferenceBuilder.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/builder/ObjectReferenceBuilder.java @@ -1,10 +1,11 @@ package pro.taskana.task.internal.builder; import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.internal.models.ObjectReferenceImpl; public class ObjectReferenceBuilder { - private final ObjectReference objectReference = new ObjectReference(); + private final ObjectReferenceImpl objectReference = new ObjectReferenceImpl(); private ObjectReferenceBuilder() {} diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/builder/TaskBuilder.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/builder/TaskBuilder.java index 4306af3cb..64bc441b5 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/builder/TaskBuilder.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/builder/TaskBuilder.java @@ -17,6 +17,7 @@ import pro.taskana.task.api.TaskCustomField; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskNotFoundException; import pro.taskana.task.api.models.Attachment; @@ -168,6 +169,11 @@ public class TaskBuilder { return this; } + public TaskBuilder objectReferences(ObjectReference... objectReferences) { + testTask.setSecondaryObjectReferences(Arrays.asList(objectReferences)); + return this; + } + public TaskBuilder customAttribute(TaskCustomField customField, String value) { testTask.setCustomAttribute(customField, value); return this; @@ -196,7 +202,7 @@ public class TaskBuilder { public Task buildAndStore(TaskService taskService) throws TaskAlreadyExistException, InvalidArgumentException, WorkbasketNotFoundException, ClassificationNotFoundException, NotAuthorizedException, AttachmentPersistenceException, - TaskNotFoundException { + ObjectReferencePersistenceException, TaskNotFoundException { try { Task task = taskService.createTask(testTask); return taskService.getTask(task.getId()); @@ -218,7 +224,7 @@ public class TaskBuilder { public TaskSummary buildAndStoreAsSummary(TaskService taskService) throws TaskAlreadyExistException, InvalidArgumentException, TaskNotFoundException, WorkbasketNotFoundException, ClassificationNotFoundException, NotAuthorizedException, - AttachmentPersistenceException { + AttachmentPersistenceException, ObjectReferencePersistenceException { return buildAndStore(taskService).asSummary(); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/AttachmentSummaryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/AttachmentSummaryImpl.java index 5cb899a08..1753ae056 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/AttachmentSummaryImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/AttachmentSummaryImpl.java @@ -121,6 +121,16 @@ public class AttachmentSummaryImpl implements AttachmentSummary { this.classificationSummary = classificationSummary; } + // auxiliary method to enable MyBatis access to objectReference + public ObjectReferenceImpl getObjectReferenceImpl() { + return (ObjectReferenceImpl) objectReference; + } + + // auxiliary method to enable MyBatis access to objectReference + public void setObjectReferenceImpl(ObjectReferenceImpl objectReferenceImpl) { + this.objectReference = objectReferenceImpl; + } + protected boolean canEqual(Object other) { return (!(other instanceof AttachmentSummaryImpl)); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/ObjectReferenceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/ObjectReferenceImpl.java new file mode 100644 index 000000000..de735d30e --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/ObjectReferenceImpl.java @@ -0,0 +1,165 @@ +package pro.taskana.task.internal.models; + +import java.util.Objects; + +import pro.taskana.common.api.exceptions.InvalidArgumentException; +import pro.taskana.task.api.models.ObjectReference; + +/** ObjectReference entity. */ +public class ObjectReferenceImpl implements ObjectReference { + private String id; + private String taskId; + private String company; + private String system; + private String systemInstance; + private String type; + private String value; + + public ObjectReferenceImpl() {} + + public ObjectReferenceImpl( + String company, String system, String systemInstance, String type, String value) { + this.company = company; + this.system = system; + this.systemInstance = systemInstance; + this.type = type; + this.value = value; + } + + private ObjectReferenceImpl(ObjectReferenceImpl copyFrom) { + company = copyFrom.company; + system = copyFrom.system; + systemInstance = copyFrom.systemInstance; + type = copyFrom.type; + value = copyFrom.value; + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + + @Override + public String getCompany() { + return company; + } + + public void setCompany(String company) { + this.company = company; + } + + @Override + public String getSystem() { + return system; + } + + public void setSystem(String system) { + this.system = system; + } + + @Override + public String getSystemInstance() { + return systemInstance; + } + + public void setSystemInstance(String systemInstance) { + this.systemInstance = systemInstance; + } + + @Override + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + @Override + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public ObjectReferenceImpl copy() { + return new ObjectReferenceImpl(this); + } + + public static void validate(ObjectReference objectReference, String objRefType, String objName) + throws InvalidArgumentException { + // check that all values in the ObjectReference are set correctly + if (objectReference == null) { + throw new InvalidArgumentException( + String.format("%s of %s must not be null.", objRefType, objName)); + } else if (objectReference.getCompany() == null || objectReference.getCompany().isEmpty()) { + throw new InvalidArgumentException( + String.format("Company of %s of %s must not be empty", objRefType, objName)); + } else if (objectReference.getType() == null || objectReference.getType().length() == 0) { + throw new InvalidArgumentException( + String.format("Type of %s of %s must not be empty", objRefType, objName)); + } else if (objectReference.getValue() == null || objectReference.getValue().length() == 0) { + throw new InvalidArgumentException( + String.format("Value of %s of %s must not be empty", objRefType, objName)); + } + } + + @Override + public int hashCode() { + return Objects.hash(id, taskId, company, system, systemInstance, type, value); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ObjectReferenceImpl)) { + return false; + } + ObjectReferenceImpl other = (ObjectReferenceImpl) obj; + return Objects.equals(id, other.id) + && Objects.equals(taskId, other.taskId) + && Objects.equals(company, other.company) + && Objects.equals(system, other.system) + && Objects.equals(systemInstance, other.systemInstance) + && Objects.equals(type, other.type) + && Objects.equals(value, other.value); + } + + @Override + public String toString() { + return "ObjectReference [" + + "id=" + + this.id + + ", taskId=" + + this.taskId + + ", company=" + + this.company + + ", system=" + + this.system + + ", systemInstance=" + + this.systemInstance + + ", type=" + + this.type + + ", value=" + + this.value + + "]"; + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskImpl.java index 8de0de3b7..45d97cfef 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskImpl.java @@ -201,6 +201,7 @@ public class TaskImpl extends TaskSummaryImpl implements Task { attSummaries.add(att.asSummary()); } taskSummary.setAttachmentSummaries(attSummaries); + taskSummary.setSecondaryObjectReferences(secondaryObjectReferences); taskSummary.setBusinessProcessId(this.businessProcessId); taskSummary.setClaimed(claimed); if (classificationSummary != null) { @@ -313,6 +314,8 @@ public class TaskImpl extends TaskSummaryImpl implements Task { + callbackState + ", attachments=" + attachments + + ", objectReferences=" + + secondaryObjectReferences + ", id=" + id + ", externalId=" diff --git a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskSummaryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskSummaryImpl.java index 886c57454..9b188f3ae 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskSummaryImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/task/internal/models/TaskSummaryImpl.java @@ -5,6 +5,7 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.stream.Collectors; import pro.taskana.classification.api.models.ClassificationSummary; import pro.taskana.classification.internal.models.ClassificationSummaryImpl; @@ -46,6 +47,7 @@ public class TaskSummaryImpl implements TaskSummary { protected boolean isTransferred; // All objects have to be serializable protected List attachmentSummaries = new ArrayList<>(); + protected List secondaryObjectReferences = new ArrayList<>(); protected String custom1; protected String custom2; protected String custom3; @@ -88,6 +90,10 @@ public class TaskSummaryImpl implements TaskSummary { isRead = copyFrom.isRead; isTransferred = copyFrom.isTransferred; attachmentSummaries = new ArrayList<>(copyFrom.attachmentSummaries); + secondaryObjectReferences = + copyFrom.secondaryObjectReferences.stream() + .map(ObjectReference::copy) + .collect(Collectors.toList()); custom1 = copyFrom.custom1; custom2 = copyFrom.custom2; custom3 = copyFrom.custom3; @@ -268,6 +274,15 @@ public class TaskSummaryImpl implements TaskSummary { this.attachmentSummaries = attachmentSummaries; } + @Override + public List getSecondaryObjectReferences() { + return secondaryObjectReferences; + } + + public void setSecondaryObjectReferences(List objectReferences) { + this.secondaryObjectReferences = objectReferences; + } + @Override public String getDomain() { return workbasketSummary == null ? null : workbasketSummary.getDomain(); @@ -325,6 +340,11 @@ public class TaskSummaryImpl implements TaskSummary { this.primaryObjRef = primaryObjRef; } + public void setPrimaryObjRef( + String company, String system, String systemInstance, String type, String value) { + this.primaryObjRef = new ObjectReferenceImpl(company, system, systemInstance, type, value); + } + @Override public boolean isRead() { return isRead; @@ -406,6 +426,50 @@ public class TaskSummaryImpl implements TaskSummary { this.attachmentSummaries.add(attachmentSummary); } + @Override + public void addSecondaryObjectReference(ObjectReference objectReferenceToAdd) { + if (secondaryObjectReferences == null) { + secondaryObjectReferences = new ArrayList<>(); + } + if (objectReferenceToAdd != null) { + ((ObjectReferenceImpl) objectReferenceToAdd).setTaskId(this.id); + if (objectReferenceToAdd.getId() != null) { + secondaryObjectReferences.removeIf( + objectReference -> objectReferenceToAdd.getId().equals(objectReference.getId())); + } + secondaryObjectReferences.add(objectReferenceToAdd); + } + } + + @Override + public void addSecondaryObjectReference( + String company, String system, String systemInstance, String type, String value) { + ObjectReferenceImpl objectReferenceToAdd = + new ObjectReferenceImpl(company, system, systemInstance, type, value); + if (secondaryObjectReferences == null) { + secondaryObjectReferences = new ArrayList<>(); + } + objectReferenceToAdd.setTaskId(this.id); + if (objectReferenceToAdd.getId() != null) { + secondaryObjectReferences.removeIf( + objectReference -> objectReferenceToAdd.getId().equals(objectReference.getId())); + } + secondaryObjectReferences.add(objectReferenceToAdd); + } + + @Override + public ObjectReference removeSecondaryObjectReference(String objectReferenceId) { + ObjectReference result = null; + for (ObjectReference objectReference : secondaryObjectReferences) { + if (objectReference.getId().equals(objectReferenceId) + && secondaryObjectReferences.remove(objectReference)) { + result = objectReference; + break; + } + } + return result; + } + // auxiliary Method to enable Mybatis to access classificationSummary public ClassificationSummaryImpl getClassificationSummaryImpl() { return (ClassificationSummaryImpl) classificationSummary; @@ -416,6 +480,16 @@ public class TaskSummaryImpl implements TaskSummary { setClassificationSummary(classificationSummary); } + // auxiliary Method to enable Mybatis to access primaryObjRef + public ObjectReferenceImpl getPrimaryObjRefImpl() { + return (ObjectReferenceImpl) primaryObjRef; + } + + // auxiliary Method to enable Mybatis to access primaryObjRef + public void setPrimaryObjRefImpl(ObjectReferenceImpl objectReference) { + setPrimaryObjRef(objectReference); + } + public String getCustom1() { return custom1; } @@ -592,6 +666,7 @@ public class TaskSummaryImpl implements TaskSummary { isRead, isTransferred, attachmentSummaries, + secondaryObjectReferences, custom1, custom2, custom3, @@ -647,6 +722,7 @@ public class TaskSummaryImpl implements TaskSummary { && Objects.equals(ownerLongName, other.ownerLongName) && Objects.equals(primaryObjRef, other.primaryObjRef) && Objects.equals(attachmentSummaries, other.attachmentSummaries) + && Objects.equals(secondaryObjectReferences, other.secondaryObjectReferences) && Objects.equals(custom1, other.custom1) && Objects.equals(custom2, other.custom2) && Objects.equals(custom3, other.custom3) @@ -717,6 +793,8 @@ public class TaskSummaryImpl implements TaskSummary { + isTransferred + ", attachmentSummaries=" + attachmentSummaries + + ", objectReferences=" + + secondaryObjectReferences + ", custom1=" + custom1 + ", custom2=" diff --git a/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java b/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java index cc3d1f7ef..64db961b7 100644 --- a/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java @@ -27,6 +27,7 @@ import pro.taskana.sampledata.SampleDataGenerator; import pro.taskana.task.api.models.Attachment; import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.internal.TaskServiceImpl; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.user.api.models.User; /** Base class for all acceptance tests. */ @@ -78,9 +79,9 @@ public abstract class AbstractAccTest { return sqlSessionManager.getMapper(JobMapper.class); } - protected ObjectReference createObjectReference( + protected ObjectReferenceImpl createObjectReference( String company, String system, String systemInstance, String type, String value) { - ObjectReference objectReference = new ObjectReference(); + ObjectReferenceImpl objectReference = new ObjectReferenceImpl(); objectReference.setCompany(company); objectReference.setSystem(system); objectReference.setSystemInstance(systemInstance); diff --git a/lib/taskana-core/src/test/java/acceptance/TaskTestMapper.java b/lib/taskana-core/src/test/java/acceptance/TaskTestMapper.java index 40a7ba99e..b81430a78 100644 --- a/lib/taskana-core/src/test/java/acceptance/TaskTestMapper.java +++ b/lib/taskana-core/src/test/java/acceptance/TaskTestMapper.java @@ -54,11 +54,11 @@ public interface TaskTestMapper { @Result(property = "businessProcessId", column = "BUSINESS_PROCESS_ID"), @Result(property = "parentBusinessProcessId", column = "PARENT_BUSINESS_PROCESS_ID"), @Result(property = "owner", column = "OWNER"), - @Result(property = "primaryObjRef.company", column = "POR_COMPANY"), - @Result(property = "primaryObjRef.system", column = "POR_SYSTEM"), - @Result(property = "primaryObjRef.systemInstance", column = "POR_INSTANCE"), - @Result(property = "primaryObjRef.type", column = "POR_TYPE"), - @Result(property = "primaryObjRef.value", column = "POR_VALUE"), + @Result(property = "primaryObjRefImpl.company", column = "POR_COMPANY"), + @Result(property = "primaryObjRefImpl.system", column = "POR_SYSTEM"), + @Result(property = "primaryObjRefImpl.systemInstance", column = "POR_INSTANCE"), + @Result(property = "primaryObjRefImpl.type", column = "POR_TYPE"), + @Result(property = "primaryObjRefImpl.value", column = "POR_VALUE"), @Result(property = "isRead", column = "IS_READ"), @Result(property = "isTransferred", column = "IS_TRANSFERRED"), @Result( diff --git a/lib/taskana-core/src/test/java/acceptance/builder/ObjectReferenceBuilderTest.java b/lib/taskana-core/src/test/java/acceptance/builder/ObjectReferenceBuilderTest.java index cf2a35cc3..9b7f15164 100644 --- a/lib/taskana-core/src/test/java/acceptance/builder/ObjectReferenceBuilderTest.java +++ b/lib/taskana-core/src/test/java/acceptance/builder/ObjectReferenceBuilderTest.java @@ -6,6 +6,7 @@ import static pro.taskana.task.internal.builder.ObjectReferenceBuilder.newObject import org.junit.jupiter.api.Test; import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.internal.models.ObjectReferenceImpl; class ObjectReferenceBuilderTest { @@ -20,7 +21,7 @@ class ObjectReferenceBuilderTest { .value("Value1") .build(); - ObjectReference expectedObjectReference = new ObjectReference(); + ObjectReferenceImpl expectedObjectReference = new ObjectReferenceImpl(); expectedObjectReference.setCompany("Company1"); expectedObjectReference.setSystem("System1"); expectedObjectReference.setSystemInstance("Instance1"); @@ -28,7 +29,7 @@ class ObjectReferenceBuilderTest { expectedObjectReference.setValue("Value1"); assertThat(objectReference) - .hasNoNullFieldsOrPropertiesExcept("id") + .hasNoNullFieldsOrPropertiesExcept("id", "taskId") .isEqualTo(expectedObjectReference); } } diff --git a/lib/taskana-core/src/test/java/acceptance/task/CreateTaskAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/CreateTaskAccTest.java index 1b37a385d..4ffecfb97 100644 --- a/lib/taskana-core/src/test/java/acceptance/task/CreateTaskAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/task/CreateTaskAccTest.java @@ -37,6 +37,7 @@ import pro.taskana.task.api.models.AttachmentSummary; import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; import pro.taskana.task.internal.AttachmentMapper; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskImpl; import pro.taskana.workbasket.api.WorkbasketService; import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; @@ -79,11 +80,14 @@ class CreateTaskAccTest extends AbstractAccTest { Task newTask = taskService.newTask("USER-1-1", "DOMAIN_A"); newTask.setClassificationKey("T2100"); - ObjectReference objectReference = + ObjectReferenceImpl objectReference = createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"); + objectReference.setTaskId(newTask.getId()); newTask.setPrimaryObjRef(objectReference); + newTask.setOwner("user-1-1"); Task createdTask = taskService.createTask(newTask); + Instant expectedPlanned = moveForwardToWorkingDay(createdTask.getCreated()); assertThat(createdTask).isNotNull(); diff --git a/lib/taskana-core/src/test/java/acceptance/task/CreateTaskWithSorAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/CreateTaskWithSorAccTest.java new file mode 100644 index 000000000..006fc44b8 --- /dev/null +++ b/lib/taskana-core/src/test/java/acceptance/task/CreateTaskWithSorAccTest.java @@ -0,0 +1,176 @@ +package acceptance.task; + +import static acceptance.DefaultTestEntities.defaultTestClassification; +import static acceptance.DefaultTestEntities.defaultTestObjectReference; +import static acceptance.DefaultTestEntities.defaultTestWorkbasket; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import acceptance.TaskanaEngineProxy; +import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import testapi.TaskanaInject; +import testapi.TaskanaIntegrationTest; + +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.api.exceptions.InvalidArgumentException; +import pro.taskana.common.test.security.WithAccessId; +import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.ObjectReferenceMapper; +import pro.taskana.task.internal.builder.ObjectReferenceBuilder; +import pro.taskana.task.internal.builder.TaskBuilder; +import pro.taskana.task.internal.models.TaskImpl; +import pro.taskana.workbasket.api.WorkbasketPermission; +import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.models.WorkbasketSummary; +import pro.taskana.workbasket.internal.builder.WorkbasketAccessItemBuilder; + +/** + * Acceptance test for all "create task" scenarios that involve secondary {@link ObjectReference}. + */ +@TaskanaIntegrationTest +class CreateTaskWithSorAccTest { + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject ClassificationService classificationService; + @TaskanaInject TaskanaEngine taskanaEngine; + + ClassificationSummary defaultClassificationSummary; + WorkbasketSummary defaultWorkbasketSummary; + ObjectReference defaultObjectReference; + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + defaultClassificationSummary = + defaultTestClassification().buildAndStoreAsSummary(classificationService); + defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(defaultWorkbasketSummary.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + defaultObjectReference = defaultTestObjectReference().build(); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_createObjectReferences_When_CreatingTask() throws Exception { + Task task = taskService.newTask(defaultWorkbasketSummary.getId()); + task.setClassificationKey(defaultClassificationSummary.getKey()); + task.setPrimaryObjRef(defaultObjectReference); + + ObjectReference sor1 = + taskService.newObjectReference( + "FirstCompany", "FirstSystem", null, "FirstType", "FirstValue"); + ObjectReference sor2 = + taskService.newObjectReference("SecondCompany", null, null, "SecondType", "SecondValue"); + + task.addSecondaryObjectReference(sor1); + task.addSecondaryObjectReference(sor2); + + Task createdTask = taskService.createTask(task); + + TaskanaEngineProxy engineProxy = new TaskanaEngineProxy(taskanaEngine); + ObjectReferenceMapper objectReferenceMapper = + engineProxy.getEngine().getSqlSession().getMapper(ObjectReferenceMapper.class); + + try { + engineProxy.openConnection(); + assertThat(objectReferenceMapper.findObjectReferencesByTaskId(createdTask.getId())) + .hasSize(2); + } finally { + engineProxy.returnConnection(); + } + + Task readTask = taskService.getTask(createdTask.getId()); + + assertThat(readTask.getSecondaryObjectReferences()) + .extracting(ObjectReference::getSystem) + .containsExactly("FirstSystem", null); + + assertThat(readTask.getSecondaryObjectReferences()) + .extracting(ObjectReference::getType) + .containsExactly("FirstType", "SecondType"); + + assertThat(readTask.getSecondaryObjectReferences()) + .extracting(ObjectReference::getValue) + .containsExactly("FirstValue", "SecondValue"); + + assertThat(readTask.getSecondaryObjectReferences()) + .extracting(ObjectReference::getCompany) + .containsExactly("FirstCompany", "SecondCompany"); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ThrowException_When_InvalidObjectReference() throws Exception { + ObjectReference sor1 = + taskService.newObjectReference( + "FirstCompany", "FirstSystem", null, "FirstType", "FirstValue"); + ObjectReference invalidSor = + taskService.newObjectReference(null, null, null, "Second Type", "Second Value"); + + TaskImpl task = (TaskImpl) taskService.newTask(defaultWorkbasketSummary.getId()); + task.setClassificationKey(defaultClassificationSummary.getKey()); + task.setPrimaryObjRef(defaultObjectReference); + task.addSecondaryObjectReference(sor1); + task.addSecondaryObjectReference(invalidSor); + assertThatThrownBy(() -> taskService.createTask(task)) + .isInstanceOf(InvalidArgumentException.class) + .hasMessage("Company of ObjectReference of Task must not be empty"); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_copyObjectReferences_When_DuplicatingTask() throws Exception { + ObjectReference sor1 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("FirstType") + .build(); + ObjectReference sor2 = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("SecondValue") + .type("SecondType") + .build(); + Task oldTask = + TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference) + .objectReferences(sor1, sor2) + .buildAndStore(taskService); + Task newTask = oldTask.copy(); + newTask = taskService.createTask(newTask); + + Task readOldTask = taskService.getTask(oldTask.getId()); + + assertThat(readOldTask.getSecondaryObjectReferences()) + .extracting(ObjectReference::getTaskId) + .containsExactly(oldTask.getId(), oldTask.getId()); + + Task readNewTask = taskService.getTask(newTask.getId()); + + assertThat(readNewTask.getSecondaryObjectReferences()) + .extracting(ObjectReference::getTaskId) + .containsExactly(newTask.getId(), newTask.getId()); + + assertThat(readNewTask.getSecondaryObjectReferences()) + .extracting(ObjectReference::getId) + .doesNotContainAnyElementsOf( + readOldTask.getSecondaryObjectReferences().stream() + .map(ObjectReference::getTaskId) + .collect(Collectors.toList())); + } +} diff --git a/lib/taskana-core/src/test/java/acceptance/task/DeleteTaskWithSorAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/DeleteTaskWithSorAccTest.java new file mode 100644 index 000000000..a01e2647e --- /dev/null +++ b/lib/taskana-core/src/test/java/acceptance/task/DeleteTaskWithSorAccTest.java @@ -0,0 +1,123 @@ +package acceptance.task; + +import static acceptance.DefaultTestEntities.defaultTestClassification; +import static acceptance.DefaultTestEntities.defaultTestObjectReference; +import static acceptance.DefaultTestEntities.defaultTestWorkbasket; +import static org.assertj.core.api.Assertions.assertThat; + +import acceptance.TaskanaEngineProxy; +import java.util.List; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import testapi.TaskanaInject; +import testapi.TaskanaIntegrationTest; + +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.api.TaskanaEngine; +import pro.taskana.common.test.security.WithAccessId; +import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.TaskState; +import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.ObjectReferenceMapper; +import pro.taskana.task.internal.builder.ObjectReferenceBuilder; +import pro.taskana.task.internal.builder.TaskBuilder; +import pro.taskana.workbasket.api.WorkbasketPermission; +import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.models.WorkbasketSummary; +import pro.taskana.workbasket.internal.builder.WorkbasketAccessItemBuilder; + +/** + * Acceptance test for all "delete task" scenarios that involve secondary {@link ObjectReference}s. + */ +@TaskanaIntegrationTest +class DeleteTaskWithSorAccTest { + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject ClassificationService classificationService; + @TaskanaInject TaskanaEngine taskanaEngine; + + ClassificationSummary defaultClassificationSummary; + WorkbasketSummary defaultWorkbasketSummary; + ObjectReference defaultObjectReference; + ObjectReference sor1; + ObjectReference sor2; + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + defaultClassificationSummary = + defaultTestClassification().buildAndStoreAsSummary(classificationService); + defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(defaultWorkbasketSummary.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + defaultObjectReference = defaultTestObjectReference().build(); + sor1 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("FirstType") + .build(); + sor2 = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("SecondValue") + .type("SecondType") + .build(); + } + + @WithAccessId(user = "admin") + @Test + void should_DeleteObjectReferences_When_DeletingTask() throws Exception { + Task createdTask = + createCompletedTask().objectReferences(sor1, sor2).buildAndStore(taskService); + taskService.deleteTask(createdTask.getId()); + TaskanaEngineProxy engineProxy = new TaskanaEngineProxy(taskanaEngine); + ObjectReferenceMapper objectReferenceMapper = + engineProxy.getEngine().getSqlSession().getMapper(ObjectReferenceMapper.class); + + try { + engineProxy.openConnection(); + assertThat(objectReferenceMapper.findObjectReferencesByTaskId(createdTask.getId())).isEmpty(); + } finally { + engineProxy.returnConnection(); + } + } + + @WithAccessId(user = "admin") + @Test + void should_DeleteObjectReferences_When_MultipleTasksAreDeleted() throws Exception { + Task firstCreatedTask = createCompletedTask().objectReferences(sor1).buildAndStore(taskService); + Task secondCreatedTask = + createCompletedTask().objectReferences(sor1, sor2).buildAndStore(taskService); + taskService.deleteTasks(List.of(firstCreatedTask.getId(), secondCreatedTask.getId())); + TaskanaEngineProxy engineProxy = new TaskanaEngineProxy(taskanaEngine); + ObjectReferenceMapper objectReferenceMapper = + engineProxy.getEngine().getSqlSession().getMapper(ObjectReferenceMapper.class); + + try { + engineProxy.openConnection(); + assertThat( + objectReferenceMapper.findObjectReferencesByTaskIds( + List.of(firstCreatedTask.getId(), secondCreatedTask.getId()))) + .isEmpty(); + } finally { + engineProxy.returnConnection(); + } + } + + private TaskBuilder createCompletedTask() { + return (TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference) + .state(TaskState.COMPLETED)); + } +} diff --git a/lib/taskana-core/src/test/java/acceptance/task/GetTaskWithSorAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/GetTaskWithSorAccTest.java new file mode 100644 index 000000000..b0b31ba3f --- /dev/null +++ b/lib/taskana-core/src/test/java/acceptance/task/GetTaskWithSorAccTest.java @@ -0,0 +1,91 @@ +package acceptance.task; + +import static acceptance.DefaultTestEntities.defaultTestClassification; +import static acceptance.DefaultTestEntities.defaultTestObjectReference; +import static acceptance.DefaultTestEntities.defaultTestWorkbasket; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import testapi.TaskanaInject; +import testapi.TaskanaIntegrationTest; + +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.test.security.WithAccessId; +import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.builder.ObjectReferenceBuilder; +import pro.taskana.task.internal.builder.TaskBuilder; +import pro.taskana.workbasket.api.WorkbasketPermission; +import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.models.WorkbasketSummary; +import pro.taskana.workbasket.internal.builder.WorkbasketAccessItemBuilder; + +@TaskanaIntegrationTest +class GetTaskWithSorAccTest { + + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject ClassificationService classificationService; + + ClassificationSummary defaultClassificationSummary; + WorkbasketSummary defaultWorkbasketSummary; + ObjectReference defaultObjectReference; + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + defaultClassificationSummary = + defaultTestClassification().buildAndStoreAsSummary(classificationService); + defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(defaultWorkbasketSummary.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + defaultObjectReference = defaultTestObjectReference().build(); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnTaskWithSor_When_RequestingTaskByTaskId() throws Exception { + Task task = + createDefaultTask() + .objectReferences( + defaultSecondaryObjectReference("0"), defaultSecondaryObjectReference("1")) + .buildAndStore(taskService); + Task result = taskService.getTask(task.getId()); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getType) + .containsExactly("Type0", "Type1"); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getValue) + .containsExactly("Value0", "Value1"); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getCompany) + .containsExactly("Company0", "Company1"); + } + + private TaskBuilder createDefaultTask() { + return (TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference)); + } + + private ObjectReference defaultSecondaryObjectReference(String suffix) { + return ObjectReferenceBuilder.newObjectReference() + .company("Company" + suffix) + .value("Value" + suffix) + .type("Type" + suffix) + .build(); + } +} diff --git a/lib/taskana-core/src/test/java/acceptance/task/TaskModelsCloneTest.java b/lib/taskana-core/src/test/java/acceptance/task/TaskModelsCloneTest.java index 5bd6902da..3b28507f8 100644 --- a/lib/taskana-core/src/test/java/acceptance/task/TaskModelsCloneTest.java +++ b/lib/taskana-core/src/test/java/acceptance/task/TaskModelsCloneTest.java @@ -13,9 +13,9 @@ import org.junit.jupiter.api.Test; import pro.taskana.task.api.models.Attachment; import pro.taskana.task.api.models.AttachmentSummary; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.internal.models.AttachmentImpl; import pro.taskana.task.internal.models.AttachmentSummaryImpl; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskCommentImpl; import pro.taskana.task.internal.models.TaskImpl; import pro.taskana.task.internal.models.TaskSummaryImpl; @@ -116,7 +116,7 @@ class TaskModelsCloneTest { @Test void should_CopyWithoutId_When_ObjectReferenceClone() { - ObjectReference dummyReference = new ObjectReference(); + ObjectReferenceImpl dummyReference = new ObjectReferenceImpl(); dummyReference.setId("dummyId"); dummyReference.setSystem("dummySystem"); dummyReference.setCompany("dummyCompany"); @@ -124,7 +124,7 @@ class TaskModelsCloneTest { dummyReference.setType("dummyType"); dummyReference.setValue("dummyValue"); - ObjectReference dummyReferenceCloned = dummyReference.copy(); + ObjectReferenceImpl dummyReferenceCloned = dummyReference.copy(); assertThat(dummyReferenceCloned).isNotEqualTo(dummyReference); dummyReferenceCloned.setId(dummyReference.getId()); diff --git a/lib/taskana-core/src/test/java/acceptance/task/TaskQueryImplAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/TaskQueryImplAccTest.java index 7dfc86d9f..99d016705 100644 --- a/lib/taskana-core/src/test/java/acceptance/task/TaskQueryImplAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/task/TaskQueryImplAccTest.java @@ -31,6 +31,7 @@ import pro.taskana.task.api.WildcardSearchField; import pro.taskana.task.api.models.Attachment; import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.TaskSummary; +import pro.taskana.task.internal.builder.ObjectReferenceBuilder; import pro.taskana.task.internal.builder.TaskAttachmentBuilder; import pro.taskana.task.internal.builder.TaskBuilder; import pro.taskana.workbasket.api.WorkbasketPermission; @@ -2429,6 +2430,532 @@ class TaskQueryImplAccTest { } } + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class QueryingObjectReferenceCombinations { + WorkbasketSummary wb; + TaskSummary taskSummary1; + TaskSummary taskSummary2; + TaskSummary taskSummary3; + TaskSummary taskSummary4; + TaskSummary taskSummary5; + TaskSummary taskSummary6; + TaskSummary taskSummary7; + + @WithAccessId(user = "user-1-1") + @BeforeAll + void setup() throws Exception { + wb = createWorkbasketWithPermission(); + ObjectReference sor1 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("FirstType") + .build(); + taskSummary1 = + taskInWorkbasket(wb).objectReferences(sor1).buildAndStoreAsSummary(taskService); + + ObjectReference sor2 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("SecondValue") + .type("SecondType") + .build(); + taskSummary2 = + taskInWorkbasket(wb).objectReferences(sor2).buildAndStoreAsSummary(taskService); + + ObjectReference sor2copy = sor2.copy(); + ObjectReference sor1copy = sor1.copy(); + taskSummary3 = + taskInWorkbasket(wb) + .objectReferences(sor2copy, sor1copy) + .buildAndStoreAsSummary(taskService); + + ObjectReference sor3 = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("SecondValue") + .type("SecondType") + .build(); + taskSummary4 = + taskInWorkbasket(wb).objectReferences(sor1, sor3).buildAndStoreAsSummary(taskService); + + ObjectReference sor4 = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("ThirdValue") + .type("ThirdType") + .build(); + taskSummary5 = + taskInWorkbasket(wb).objectReferences(sor4).buildAndStoreAsSummary(taskService); + + ObjectReference sor5 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("ThirdValue") + .type("FirstType") + .build(); + taskSummary6 = + taskInWorkbasket(wb).objectReferences(sor5).buildAndStoreAsSummary(taskService); + + ObjectReference sor6 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("ThirdType") + .build(); + taskSummary7 = + taskInWorkbasket(wb).objectReferences(sor6).buildAndStoreAsSummary(taskService); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForValueInCompanyIn() { + List tasks = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorValueIn("SecondValue") + .sorCompanyIn("FirstCompany") + .list(); + + assertThat(tasks).hasSize(2); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForValueInMultipleCompanyIn() { + List tasks = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorValueIn("SecondValue") + .sorCompanyIn("FirstCompany", "SecondCompany") + .list(); + + assertThat(tasks).hasSize(3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForValueInMultipleTypeLikeMultiple() { + List tasks = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorValueIn("FirstValue", "ThirdValue") + .sorTypeLike("First%", "Third%") + .list(); + + assertThat(tasks).hasSize(5); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class ObjectReferenceValue { + WorkbasketSummary wb; + TaskSummary taskSummary1; + TaskSummary taskSummary2; + TaskSummary taskSummary3; + + @WithAccessId(user = "user-1-1") + @BeforeAll + void setup() throws Exception { + wb = createWorkbasketWithPermission(); + ObjectReference sor1 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("FirstType") + .build(); + ObjectReference sor2 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("SecondValue") + .type("SecondType") + .build(); + + ObjectReference sor2copy = sor2.copy(); + ObjectReference sor1copy = sor1.copy(); + + taskSummary1 = + taskInWorkbasket(wb).objectReferences(sor1).buildAndStoreAsSummary(taskService); + taskSummary2 = + taskInWorkbasket(wb).objectReferences(sor2).buildAndStoreAsSummary(taskService); + taskSummary3 = + taskInWorkbasket(wb) + .objectReferences(sor2copy, sor1copy) + .buildAndStoreAsSummary(taskService); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForValueIn() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorValueIn("FirstValue") + .list(); + + assertThat(list).containsExactlyInAnyOrder(taskSummary1, taskSummary3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_CountCorrectly_When_QueryingForValueIn() { + long numberOfTasks = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorValueIn("FirstValue") + .count(); + + assertThat(numberOfTasks).isEqualTo(2); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForValueLike() { + List list = + taskService.createTaskQuery().workbasketIdIn(wb.getId()).sorValueLike("%Value").list(); + assertThat(list).containsExactlyInAnyOrder(taskSummary1, taskSummary2, taskSummary3); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class ObjectReferenceType { + WorkbasketSummary wb; + TaskSummary taskSummary1; + TaskSummary taskSummary2; + TaskSummary taskSummary3; + TaskSummary taskSummary4; + + @WithAccessId(user = "user-1-1") + @BeforeAll + void setup() throws Exception { + wb = createWorkbasketWithPermission(); + ObjectReference sor1 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("FirstType") + .build(); + taskSummary1 = + taskInWorkbasket(wb).objectReferences(sor1).buildAndStoreAsSummary(taskService); + + ObjectReference sor2 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("SecondType") + .build(); + taskSummary2 = + taskInWorkbasket(wb).objectReferences(sor2).buildAndStoreAsSummary(taskService); + + ObjectReference sor2copy = sor2.copy(); + ObjectReference sor1copy = sor1.copy(); + taskSummary3 = + taskInWorkbasket(wb) + .objectReferences(sor2copy, sor1copy) + .buildAndStoreAsSummary(taskService); + + ObjectReference sor3 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("ThirdType") + .build(); + taskSummary4 = + taskInWorkbasket(wb).objectReferences(sor3).buildAndStoreAsSummary(taskService); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForTypeIn() { + List list = + taskService.createTaskQuery().workbasketIdIn(wb.getId()).sorTypeIn("FirstType").list(); + + assertThat(list).containsExactlyInAnyOrder(taskSummary1, taskSummary3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnSingleTaskSummary_When_QueryingForTypeLikeUsingSingle() { + TaskSummary result = + taskService.createTaskQuery().workbasketIdIn(wb.getId()).sorTypeLike("Third%").single(); + assertThat(result).isEqualTo(taskSummary4); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnEmptyList_When_QueryingForNonexistentTypeLike() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorTypeLike("%NoSuchType") + .list(); + assertThat(list).isEmpty(); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class ObjectReferenceCompany { + WorkbasketSummary wb; + TaskSummary taskSummary1; + TaskSummary taskSummary2; + TaskSummary taskSummary3; + + @WithAccessId(user = "user-1-1") + @BeforeAll + void setup() throws Exception { + wb = createWorkbasketWithPermission(); + ObjectReference sor1 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("FirstType") + .build(); + ObjectReference sor2 = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("FirstValue") + .type("SecondType") + .build(); + ObjectReference sor2copy = sor2.copy(); + ObjectReference sor1copy = sor1.copy(); + + taskSummary1 = + taskInWorkbasket(wb).objectReferences(sor1).buildAndStoreAsSummary(taskService); + taskSummary2 = + taskInWorkbasket(wb).objectReferences(sor2).buildAndStoreAsSummary(taskService); + taskSummary3 = + taskInWorkbasket(wb) + .objectReferences(sor2copy, sor1copy) + .buildAndStoreAsSummary(taskService); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForCompanyInWithLimit() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorCompanyIn("FirstCompany") + .list(0, 1); + assertThat(list).hasSize(1).containsAnyOf(taskSummary1, taskSummary3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForCompanyLike() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorCompanyLike("%Company") + .list(); + assertThat(list).containsExactlyInAnyOrder(taskSummary1, taskSummary2, taskSummary3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnEmptyList_When_QueryingForNonexistentCompanyLike() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorCompanyLike("%NoSuchCompany") + .list(); + assertThat(list).isEmpty(); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class ObjectReferenceSystem { + WorkbasketSummary wb; + TaskSummary taskSummary1; + TaskSummary taskSummary2; + TaskSummary taskSummary3; + TaskSummary taskSummary4; + + @WithAccessId(user = "user-1-1") + @BeforeAll + void setup() throws Exception { + wb = createWorkbasketWithPermission(); + ObjectReference sor1 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("FirstType") + .system("FirstSystem") + .build(); + taskSummary1 = + taskInWorkbasket(wb).objectReferences(sor1).buildAndStoreAsSummary(taskService); + + ObjectReference sor2 = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("FirstValue") + .type("SecondType") + .system("SecondSystem") + .build(); + taskSummary2 = + taskInWorkbasket(wb).objectReferences(sor2).buildAndStoreAsSummary(taskService); + + ObjectReference sor2copy = sor2.copy(); + ObjectReference sor1copy = sor1.copy(); + taskSummary3 = + taskInWorkbasket(wb) + .objectReferences(sor2copy, sor1copy) + .buildAndStoreAsSummary(taskService); + + ObjectReference objRefNoSystem = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("FirstValue") + .type("SecondType") + .build(); + taskSummary4 = + taskInWorkbasket(wb) + .objectReferences(objRefNoSystem) + .buildAndStoreAsSummary(taskService); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForSystemIn() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorSystemIn("FirstSystem") + .list(); + + assertThat(list).containsExactlyInAnyOrder(taskSummary1, taskSummary3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForSystemLike() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorSystemLike("%System") + .list(); + assertThat(list).containsExactlyInAnyOrder(taskSummary1, taskSummary2, taskSummary3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnEmptyList_When_QueryingForNonexistentSystemLike() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorSystemLike("%NoSuchSystem") + .list(); + assertThat(list).isEmpty(); + } + } + + @Nested + @TestInstance(Lifecycle.PER_CLASS) + class ObjectReferenceSystemInstance { + WorkbasketSummary wb; + TaskSummary taskSummary1; + TaskSummary taskSummary2; + TaskSummary taskSummary3; + TaskSummary taskSummary4; + + @WithAccessId(user = "user-1-1") + @BeforeAll + void setup() throws Exception { + wb = createWorkbasketWithPermission(); + ObjectReference sor1 = + ObjectReferenceBuilder.newObjectReference() + .company("FirstCompany") + .value("FirstValue") + .type("FirstType") + .systemInstance("FirstSystemInstance") + .build(); + taskSummary1 = + taskInWorkbasket(wb).objectReferences(sor1).buildAndStoreAsSummary(taskService); + + ObjectReference sor2 = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("FirstValue") + .type("SecondType") + .systemInstance("SecondSystemInstance") + .build(); + taskSummary2 = + taskInWorkbasket(wb).objectReferences(sor2).buildAndStoreAsSummary(taskService); + + ObjectReference sor2copy = sor2.copy(); + ObjectReference sor1copy = sor1.copy(); + taskSummary3 = + taskInWorkbasket(wb) + .objectReferences(sor2copy, sor1copy) + .buildAndStoreAsSummary(taskService); + + ObjectReference objRefNoSystem = + ObjectReferenceBuilder.newObjectReference() + .company("SecondCompany") + .value("FirstValue") + .type("SecondType") + .build(); + taskSummary4 = + taskInWorkbasket(wb) + .objectReferences(objRefNoSystem) + .buildAndStoreAsSummary(taskService); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForSystemInstanceIn() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorSystemInstanceIn("FirstSystemInstance") + .list(); + + assertThat(list).containsExactlyInAnyOrder(taskSummary1, taskSummary3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ApplyFilter_When_QueryingForSystemInstanceLike() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorSystemInstanceLike("%SystemInstance") + .list(); + assertThat(list).containsExactlyInAnyOrder(taskSummary1, taskSummary2, taskSummary3); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_ReturnEmptyList_When_QueryingForNonexistentSystemInstanceLike() { + List list = + taskService + .createTaskQuery() + .workbasketIdIn(wb.getId()) + .sorSystemInstanceLike("%NoSuchSystemInstance") + .list(); + assertThat(list).isEmpty(); + } + } + @Nested @TestInstance(Lifecycle.PER_CLASS) class CustomAttributes {} diff --git a/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskAccTest.java index f418a3a88..5a09e94f8 100644 --- a/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskAccTest.java @@ -31,9 +31,9 @@ import pro.taskana.common.test.security.WithAccessId; import pro.taskana.task.api.TaskCustomField; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.exceptions.TaskNotFoundException; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; import pro.taskana.task.api.models.TaskSummary; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskImpl; /** Acceptance test for all "update task" scenarios. */ @@ -258,7 +258,7 @@ class UpdateTaskAccTest extends AbstractAccTest { @Test void should_UpdateNoTasks_When_UpdateTasksWithUnmatchedObjectReferenceWasCalled() throws Exception { - ObjectReference por = new ObjectReference(); + ObjectReferenceImpl por = new ObjectReferenceImpl(); por.setCompany("00"); por.setSystem("PASystem"); por.setSystemInstance("00"); @@ -277,7 +277,7 @@ class UpdateTaskAccTest extends AbstractAccTest { @WithAccessId(user = "teamlead-1") @Test void should_UpdateTasks_When_MatchingPrimaryObjectReferenceWasChanged() throws Exception { - ObjectReference por = new ObjectReference(); + ObjectReferenceImpl por = new ObjectReferenceImpl(); por.setCompany("00"); por.setSystem("PASystem"); por.setSystemInstance("00"); diff --git a/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskWithSorAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskWithSorAccTest.java new file mode 100644 index 000000000..970c84f35 --- /dev/null +++ b/lib/taskana-core/src/test/java/acceptance/task/UpdateTaskWithSorAccTest.java @@ -0,0 +1,169 @@ +package acceptance.task; + +import static acceptance.DefaultTestEntities.defaultTestClassification; +import static acceptance.DefaultTestEntities.defaultTestObjectReference; +import static acceptance.DefaultTestEntities.defaultTestWorkbasket; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import testapi.TaskanaInject; +import testapi.TaskanaIntegrationTest; + +import pro.taskana.classification.api.ClassificationService; +import pro.taskana.classification.api.models.ClassificationSummary; +import pro.taskana.common.test.security.WithAccessId; +import pro.taskana.task.api.TaskService; +import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.builder.ObjectReferenceBuilder; +import pro.taskana.task.internal.builder.TaskBuilder; +import pro.taskana.workbasket.api.WorkbasketPermission; +import pro.taskana.workbasket.api.WorkbasketService; +import pro.taskana.workbasket.api.models.WorkbasketSummary; +import pro.taskana.workbasket.internal.builder.WorkbasketAccessItemBuilder; + +/** Acceptance test for "update task" scenarios that involve secondary {@link ObjectReference}s. */ +@TaskanaIntegrationTest +class UpdateTaskWithSorAccTest { + + @TaskanaInject TaskService taskService; + @TaskanaInject WorkbasketService workbasketService; + @TaskanaInject ClassificationService classificationService; + + ClassificationSummary defaultClassificationSummary; + WorkbasketSummary defaultWorkbasketSummary; + ObjectReference defaultObjectReference; + + @WithAccessId(user = "businessadmin") + @BeforeAll + void setup() throws Exception { + defaultClassificationSummary = + defaultTestClassification().buildAndStoreAsSummary(classificationService); + defaultWorkbasketSummary = defaultTestWorkbasket().buildAndStoreAsSummary(workbasketService); + + WorkbasketAccessItemBuilder.newWorkbasketAccessItem() + .workbasketId(defaultWorkbasketSummary.getId()) + .accessId("user-1-1") + .permission(WorkbasketPermission.OPEN) + .permission(WorkbasketPermission.READ) + .permission(WorkbasketPermission.APPEND) + .buildAndStore(workbasketService); + defaultObjectReference = defaultTestObjectReference().build(); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_NotChangeSor_When_UpdateWithoutChanges() throws Exception { + Task task = + createDefaultTask() + .objectReferences( + defaultSecondaryObjectReference("0"), defaultSecondaryObjectReference("1")) + .buildAndStore(taskService); + taskService.updateTask(task); + Task result = taskService.getTask(task.getId()); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getType) + .containsExactlyInAnyOrder("Type0", "Type1"); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getValue) + .containsExactlyInAnyOrder("Value0", "Value1"); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getCompany) + .containsExactlyInAnyOrder("Company0", "Company1"); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_UpdateExistingSor_When_SorChangedInUpdatedTask() throws Exception { + Task task = + createDefaultTask() + .objectReferences( + defaultSecondaryObjectReference("0"), defaultSecondaryObjectReference("1")) + .buildAndStore(taskService); + + ObjectReference sorToUpdate = task.getSecondaryObjectReferences().get(0); + sorToUpdate.setType("NewType"); + + taskService.updateTask(task); + Task result = taskService.getTask(task.getId()); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getType) + .containsExactlyInAnyOrder("NewType", "Type1"); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_AddNewSor_When_UpdatedTaskContainsNewSor() throws Exception { + Task task = + createDefaultTask() + .objectReferences( + defaultSecondaryObjectReference("0"), defaultSecondaryObjectReference("1")) + .buildAndStore(taskService); + task.addSecondaryObjectReference("NewCompany", null, null, "NewType", "NewValue"); + taskService.updateTask(task); + Task result = taskService.getTask(task.getId()); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getType) + .containsExactlyInAnyOrder("Type0", "Type1", "NewType"); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getValue) + .containsExactlyInAnyOrder("Value0", "Value1", "NewValue"); + + assertThat(result.getSecondaryObjectReferences()) + .extracting(ObjectReference::getCompany) + .containsExactlyInAnyOrder("Company0", "Company1", "NewCompany"); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_DeleteOneSor_When_UpdatedTaskContainsOneLessSor() throws Exception { + Task task = + createDefaultTask() + .objectReferences( + defaultSecondaryObjectReference("0"), defaultSecondaryObjectReference("1")) + .buildAndStore(taskService); + task.removeSecondaryObjectReference(task.getSecondaryObjectReferences().get(0).getId()); + taskService.updateTask(task); + Task result = taskService.getTask(task.getId()); + + assertThat(result.getSecondaryObjectReferences()).hasSize(1); + } + + @WithAccessId(user = "user-1-1") + @Test + void should_DeleteAllSor_When_UpdatedTaskContainsNoSor() throws Exception { + Task task = + createDefaultTask() + .objectReferences( + defaultSecondaryObjectReference("0"), defaultSecondaryObjectReference("1")) + .buildAndStore(taskService); + task.removeSecondaryObjectReference(task.getSecondaryObjectReferences().get(0).getId()); + task.removeSecondaryObjectReference(task.getSecondaryObjectReferences().get(0).getId()); + taskService.updateTask(task); + Task result = taskService.getTask(task.getId()); + + assertThat(result.getSecondaryObjectReferences()).isEmpty(); + } + + private TaskBuilder createDefaultTask() { + return (TaskBuilder.newTask() + .classificationSummary(defaultClassificationSummary) + .workbasketSummary(defaultWorkbasketSummary) + .primaryObjRef(defaultObjectReference)); + } + + private ObjectReference defaultSecondaryObjectReference(String suffix) { + return ObjectReferenceBuilder.newObjectReference() + .company("Company" + suffix) + .value("Value" + suffix) + .type("Type" + suffix) + .build(); + } +} diff --git a/lib/taskana-spring-example/src/main/java/pro/taskana/example/ExampleBootstrap.java b/lib/taskana-spring-example/src/main/java/pro/taskana/example/ExampleBootstrap.java index 7716d6d35..1d19a3e26 100644 --- a/lib/taskana-spring-example/src/main/java/pro/taskana/example/ExampleBootstrap.java +++ b/lib/taskana-spring-example/src/main/java/pro/taskana/example/ExampleBootstrap.java @@ -17,10 +17,11 @@ import pro.taskana.task.api.TaskService; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; import pro.taskana.task.api.exceptions.InvalidOwnerException; import pro.taskana.task.api.exceptions.InvalidStateException; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskNotFoundException; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.workbasket.api.WorkbasketType; import pro.taskana.workbasket.api.exceptions.WorkbasketAlreadyExistException; import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; @@ -41,7 +42,7 @@ public class ExampleBootstrap { NotAuthorizedException, ClassificationAlreadyExistException, MalformedServiceLevelException, TaskAlreadyExistException, WorkbasketNotFoundException, ClassificationNotFoundException, AttachmentPersistenceException, TaskNotFoundException, - InvalidOwnerException, InvalidStateException { + InvalidOwnerException, InvalidStateException, ObjectReferencePersistenceException { System.out.println("---------------------------> Start App"); Workbasket wb = taskanaEngine.getWorkbasketService().newWorkbasket("workbasket", "DOMAIN_A"); @@ -56,7 +57,7 @@ public class ExampleBootstrap { Task task = taskanaEngine.getTaskService().newTask(wb.getId()); task.setName("Spring example task"); task.setClassificationKey(classification.getKey()); - ObjectReference objRef = new ObjectReference(); + ObjectReferenceImpl objRef = new ObjectReferenceImpl(); objRef.setCompany("aCompany"); objRef.setSystem("aSystem"); objRef.setSystemInstance("anInstance"); diff --git a/lib/taskana-spring-example/src/test/java/pro/taskana/example/TaskanaTransactionIntTest.java b/lib/taskana-spring-example/src/test/java/pro/taskana/example/TaskanaTransactionIntTest.java index bba869880..5372dd434 100644 --- a/lib/taskana-spring-example/src/test/java/pro/taskana/example/TaskanaTransactionIntTest.java +++ b/lib/taskana-spring-example/src/test/java/pro/taskana/example/TaskanaTransactionIntTest.java @@ -31,6 +31,7 @@ import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; import pro.taskana.task.api.models.TaskSummary; import pro.taskana.task.internal.jobs.TaskCleanupJob; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskImpl; import pro.taskana.workbasket.api.WorkbasketService; import pro.taskana.workbasket.api.WorkbasketType; @@ -230,7 +231,7 @@ class TaskanaTransactionIntTest { } private static ObjectReference createDefaultObjRef() { - ObjectReference objRef = new ObjectReference(); + ObjectReferenceImpl objRef = new ObjectReferenceImpl(); objRef.setCompany("company"); objRef.setSystem("system"); objRef.setSystemInstance("instance"); diff --git a/lib/taskana-spring/src/test/java/pro/taskana/common/internal/transaction/TaskanaComponent.java b/lib/taskana-spring/src/test/java/pro/taskana/common/internal/transaction/TaskanaComponent.java index f269f3e1b..327504ee9 100644 --- a/lib/taskana-spring/src/test/java/pro/taskana/common/internal/transaction/TaskanaComponent.java +++ b/lib/taskana-spring/src/test/java/pro/taskana/common/internal/transaction/TaskanaComponent.java @@ -9,9 +9,10 @@ import pro.taskana.common.api.exceptions.InvalidArgumentException; import pro.taskana.common.api.exceptions.NotAuthorizedException; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.workbasket.api.exceptions.WorkbasketNotFoundException; /** TODO. */ @@ -27,10 +28,11 @@ public class TaskanaComponent { public void triggerRollback() throws NotAuthorizedException, WorkbasketNotFoundException, ClassificationNotFoundException, - TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException { + TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, + ObjectReferencePersistenceException { Task task = taskService.newTask("1"); task.setName("Unit Test Task"); - ObjectReference objRef = new ObjectReference(); + ObjectReferenceImpl objRef = new ObjectReferenceImpl(); objRef.setCompany("aCompany"); objRef.setSystem("aSystem"); objRef.setSystemInstance("anInstance"); diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/JsonPropertyEditorRegistrator.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/JsonPropertyEditorRegistrator.java index 0dfde34c7..49105b954 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/JsonPropertyEditorRegistrator.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/common/rest/JsonPropertyEditorRegistrator.java @@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.InitBinder; import pro.taskana.monitor.rest.models.PriorityColumnHeaderRepresentationModel; import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.internal.models.ObjectReferenceImpl; @ControllerAdvice public class JsonPropertyEditorRegistrator { @@ -25,6 +26,6 @@ public class JsonPropertyEditorRegistrator { PriorityColumnHeaderRepresentationModel.class, new JsonPropertyEditor(objectMapper, PriorityColumnHeaderRepresentationModel.class)); binder.registerCustomEditor( - ObjectReference.class, new JsonPropertyEditor(objectMapper, ObjectReference.class)); + ObjectReference.class, new JsonPropertyEditor(objectMapper, ObjectReferenceImpl.class)); } } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java index a1d35896b..4cc5a4a39 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskController.java @@ -37,6 +37,7 @@ import pro.taskana.task.api.TaskService; import pro.taskana.task.api.exceptions.AttachmentPersistenceException; import pro.taskana.task.api.exceptions.InvalidOwnerException; import pro.taskana.task.api.exceptions.InvalidStateException; +import pro.taskana.task.api.exceptions.ObjectReferencePersistenceException; import pro.taskana.task.api.exceptions.TaskAlreadyExistException; import pro.taskana.task.api.exceptions.TaskNotFoundException; import pro.taskana.task.api.models.Task; @@ -84,13 +85,11 @@ public class TaskController { TaskQueryFilterParameter filterParameter, TaskQuerySortParameter sortParameter, QueryPagingParameter pagingParameter) { - QueryParamsValidator.validateParams( request, TaskQueryFilterParameter.class, QuerySortParameter.class, QueryPagingParameter.class); - TaskQuery query = taskService.createTaskQuery(); filterParameter.apply(query); @@ -332,6 +331,8 @@ public class TaskController { * @throws InvalidArgumentException if any input is semantically wrong. * @throws AttachmentPersistenceException if an Attachment with ID will be added multiple times * without using the task-methods + * @throws ObjectReferencePersistenceException if an ObjectReference with ID will be added + * multiple times without using the task-methods * @title Create a new Task */ @PostMapping(path = RestEndpoints.URL_TASKS) @@ -339,7 +340,8 @@ public class TaskController { public ResponseEntity createTask( @RequestBody TaskRepresentationModel taskRepresentationModel) throws WorkbasketNotFoundException, ClassificationNotFoundException, NotAuthorizedException, - TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException { + TaskAlreadyExistException, InvalidArgumentException, AttachmentPersistenceException, + ObjectReferencePersistenceException { Task fromResource = taskRepresentationModelAssembler.toEntityModel(taskRepresentationModel); Task createdTask = taskService.createTask(fromResource); @@ -388,6 +390,8 @@ public class TaskController { * @throws NotAuthorizedException if the current user is not authorized. * @throws AttachmentPersistenceException if the modified Task contains two attachments with the * same id. + * @throws ObjectReferencePersistenceException if the modified Task contains two object references + * with the same id. * @throws InvalidStateException if an attempt is made to change the owner of the Task and the * Task is not in state READY. * @title Update a Task @@ -399,7 +403,7 @@ public class TaskController { @RequestBody TaskRepresentationModel taskRepresentationModel) throws TaskNotFoundException, ClassificationNotFoundException, InvalidArgumentException, ConcurrencyException, NotAuthorizedException, AttachmentPersistenceException, - InvalidStateException { + InvalidStateException, ObjectReferencePersistenceException { if (!taskId.equals(taskRepresentationModel.getTaskId())) { throw new InvalidArgumentException( String.format( diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskQueryFilterParameter.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskQueryFilterParameter.java index 1ed7e3370..bf0d3e39c 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskQueryFilterParameter.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/TaskQueryFilterParameter.java @@ -859,6 +859,91 @@ public class TaskQueryFilterParameter implements QueryParameter */ @JsonProperty("por-value-not-like") private final String[] porValueNotLike; + // endregion + // region secondaryObjectReference + /** + * Filter by the primary object reference of the task. This is an exact match. "sor" is a + * parameter of complex type. Its following attributes from sor[].id to sor[].value can be + * specified according to the description of complex parameters in the overview, e.g. + * sor={"value":"exampleValue"} + */ + @JsonProperty("sor") + private final ObjectReference[] secondaryObjectReferenceIn; + // endregion + // region secondaryObjectReferenceCompany + /** + * Filter by the company of the secondary object reference of the task. This is an exact match. + */ + @JsonProperty("sor-company") + private final String[] sorCompanyIn; + + /** + * Filter by the company of the secondary object references of the task. This results in a + * substring search (% is appended to the front and end of the requested value). Further SQL + * "LIKE" wildcard characters will be resolved correctly. + */ + @JsonProperty("sor-company-like") + private final String[] sorCompanyLike; + + // endregion + // region secondaryObjectReferenceSystem + /** Filter by the system of the secondary object reference of the task. This is an exact match. */ + @JsonProperty("sor-system") + private final String[] sorSystemIn; + + /** + * Filter by the system of the secondary object reference of the task. This results in a substring + * search (% is appended to the front and end of the requested value). Further SQL "LIKE" wildcard + * characters will be resolved correctly. + */ + @JsonProperty("sor-system-like") + private final String[] sorSystemLike; + + // endregion + // region secondaryObjectReferenceSystemInstance + /** + * Filter by the system instance of the secondary object reference of the task. This is an exact + * match. + */ + @JsonProperty("sor-instance") + private final String[] sorInstanceIn; + + /** + * Filter by the system instance of the secondary object reference of the task. This results in a + * substring search (% is appended to the front and end of the requested value). Further SQL + * "LIKE" wildcard characters will be resolved correctly. + */ + @JsonProperty("sor-instance-like") + private final String[] sorInstanceLike; + + // endregion + // region secondaryObjectReferenceSystemType + /** Filter by the type of the secondary object reference of the task. This is an exact match. */ + @JsonProperty("sor-type") + private final String[] sorTypeIn; + + /** + * Filter by the type of the secondary object reference of the task. This results in a substring + * search (% is appended to the front and end of the requested value). Further SQL "LIKE" wildcard + * characters will be resolved correctly. + */ + @JsonProperty("sor-type-like") + private final String[] sorTypeLike; + + // endregion + // region primaryObjectReferenceSystemValue + /** Filter by the value of the secondary object reference of the task. This is an exact match. */ + @JsonProperty("sor-value") + private final String[] sorValueIn; + + /** + * Filter by the value of the secondary object reference of the task. This results in a substring + * search (% is appended to the front and end of the requested value). Further SQL "LIKE" wildcard + * characters will be resolved correctly. + */ + @JsonProperty("sor-value-like") + private final String[] sorValueLike; + // endregion // region read /** Filter by the is read flag of the task. This is an exact match. */ @@ -1527,6 +1612,17 @@ public class TaskQueryFilterParameter implements QueryParameter "por-value-not", "por-value-like", "por-value-not-like", + "sor", + "sor-company", + "sor-company-like", + "sor-system", + "sor-system-like", + "sor-instance", + "sor-instance-like", + "sor-type", + "sor-type-like", + "sor-value", + "sor-value-like", "is-read", "is-transferred", "attachment-classification-id", @@ -1725,6 +1821,17 @@ public class TaskQueryFilterParameter implements QueryParameter String[] porValueNotIn, String[] porValueLike, String[] porValueNotLike, + ObjectReference[] secondaryObjectReferenceIn, + String[] sorCompanyIn, + String[] sorCompanyLike, + String[] sorSystemIn, + String[] sorSystemLike, + String[] sorInstanceIn, + String[] sorInstanceLike, + String[] sorTypeIn, + String[] sorTypeLike, + String[] sorValueIn, + String[] sorValueLike, Boolean isRead, Boolean isTransferred, String[] attachmentClassificationIdIn, @@ -1922,6 +2029,17 @@ public class TaskQueryFilterParameter implements QueryParameter this.porValueNotIn = porValueNotIn; this.porValueLike = porValueLike; this.porValueNotLike = porValueNotLike; + this.secondaryObjectReferenceIn = secondaryObjectReferenceIn; + this.sorCompanyIn = sorCompanyIn; + this.sorCompanyLike = sorCompanyLike; + this.sorSystemIn = sorSystemIn; + this.sorSystemLike = sorSystemLike; + this.sorInstanceIn = sorInstanceIn; + this.sorInstanceLike = sorInstanceLike; + this.sorTypeIn = sorTypeIn; + this.sorTypeLike = sorTypeLike; + this.sorValueIn = sorValueIn; + this.sorValueLike = sorValueLike; this.isRead = isRead; this.isTransferred = isTransferred; this.attachmentClassificationIdIn = attachmentClassificationIdIn; @@ -2261,6 +2379,31 @@ public class TaskQueryFilterParameter implements QueryParameter .map(this::wrapElementsInLikeStatement) .ifPresent(query::primaryObjectReferenceValueNotLike); + Optional.ofNullable(secondaryObjectReferenceIn).ifPresent(query::secondaryObjectReferenceIn); + + Optional.ofNullable(sorCompanyIn).ifPresent(query::sorCompanyIn); + Optional.ofNullable(sorCompanyLike) + .map(this::wrapElementsInLikeStatement) + .ifPresent(query::sorCompanyLike); + + Optional.ofNullable(sorSystemIn).ifPresent(query::sorSystemIn); + Optional.ofNullable(sorSystemLike) + .map(this::wrapElementsInLikeStatement) + .ifPresent(query::sorSystemLike); + + Optional.ofNullable(sorInstanceIn).ifPresent(query::sorSystemInstanceIn); + Optional.ofNullable(sorInstanceLike) + .map(this::wrapElementsInLikeStatement) + .ifPresent(query::sorSystemInstanceLike); + Optional.ofNullable(sorTypeIn).ifPresent(query::sorTypeIn); + Optional.ofNullable(sorTypeLike) + .map(this::wrapElementsInLikeStatement) + .ifPresent(query::sorTypeLike); + Optional.ofNullable(sorValueIn).ifPresent(query::sorValueIn); + Optional.ofNullable(sorValueLike) + .map(this::wrapElementsInLikeStatement) + .ifPresent(query::sorValueLike); + Optional.ofNullable(isRead).ifPresent(query::readEquals); Optional.ofNullable(isTransferred).ifPresent(query::transferredEquals); diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/ObjectReferenceRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/ObjectReferenceRepresentationModelAssembler.java index 838ec4276..e0e8cd363 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/ObjectReferenceRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/ObjectReferenceRepresentationModelAssembler.java @@ -5,6 +5,7 @@ import org.springframework.lang.NonNull; import org.springframework.stereotype.Controller; import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.rest.models.ObjectReferenceRepresentationModel; @Controller @@ -16,6 +17,7 @@ public class ObjectReferenceRepresentationModelAssembler public ObjectReferenceRepresentationModel toModel(@NonNull ObjectReference entity) { ObjectReferenceRepresentationModel repModel = new ObjectReferenceRepresentationModel(); repModel.setId(entity.getId()); + repModel.setTaskId(entity.getTaskId()); repModel.setCompany(entity.getCompany()); repModel.setSystem(entity.getSystem()); repModel.setSystemInstance(entity.getSystemInstance()); @@ -25,8 +27,9 @@ public class ObjectReferenceRepresentationModelAssembler } public ObjectReference toEntity(ObjectReferenceRepresentationModel repModel) { - ObjectReference objectReference = new ObjectReference(); + ObjectReferenceImpl objectReference = new ObjectReferenceImpl(); objectReference.setId(repModel.getId()); + objectReference.setTaskId(repModel.getTaskId()); objectReference.setCompany(repModel.getCompany()); objectReference.setSystem(repModel.getSystem()); objectReference.setSystemInstance(repModel.getSystemInstance()); diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssembler.java index b953f58a1..3d53476b0 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssembler.java @@ -74,6 +74,10 @@ public class TaskRepresentationModelAssembler repModel.setOwner(task.getOwner()); repModel.setOwnerLongName(task.getOwnerLongName()); repModel.setPrimaryObjRef(objectReferenceAssembler.toModel(task.getPrimaryObjRef())); + repModel.setSecondaryObjectReferences( + task.getSecondaryObjectReferences().stream() + .map(objectReferenceAssembler::toModel) + .collect(Collectors.toList())); repModel.setRead(task.isRead()); repModel.setTransferred(task.isTransferred()); repModel.setAttachments( @@ -164,6 +168,10 @@ public class TaskRepresentationModelAssembler repModel.getAttachments().stream() .map(attachmentAssembler::toEntityModel) .collect(Collectors.toList())); + task.setSecondaryObjectReferences( + repModel.getSecondaryObjectReferences().stream() + .map(objectReferenceAssembler::toEntity) + .collect(Collectors.toList())); task.setCustomAttributeMap( repModel.getCustomAttributes().stream() .collect(Collectors.toMap(CustomAttribute::getKey, CustomAttribute::getValue))); diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskSummaryRepresentationModelAssembler.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskSummaryRepresentationModelAssembler.java index 2b8c98c82..9d008f503 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskSummaryRepresentationModelAssembler.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/assembler/TaskSummaryRepresentationModelAssembler.java @@ -75,6 +75,10 @@ public class TaskSummaryRepresentationModelAssembler repModel.setOwner(taskSummary.getOwner()); repModel.setOwnerLongName(taskSummary.getOwnerLongName()); repModel.setPrimaryObjRef(objectReferenceAssembler.toModel(taskSummary.getPrimaryObjRef())); + repModel.setSecondaryObjectReferences( + taskSummary.getSecondaryObjectReferences().stream() + .map(objectReferenceAssembler::toModel) + .collect(Collectors.toList())); repModel.setRead(taskSummary.isRead()); repModel.setTransferred(taskSummary.isTransferred()); repModel.setAttachmentSummaries( @@ -128,6 +132,10 @@ public class TaskSummaryRepresentationModelAssembler taskSummary.setOwner(repModel.getOwner()); taskSummary.setOwnerLongName(repModel.getOwnerLongName()); taskSummary.setPrimaryObjRef(objectReferenceAssembler.toEntity(repModel.getPrimaryObjRef())); + taskSummary.setSecondaryObjectReferences( + repModel.getSecondaryObjectReferences().stream() + .map(objectReferenceAssembler::toEntity) + .collect(Collectors.toList())); taskSummary.setRead(repModel.isRead()); taskSummary.setTransferred(repModel.isTransferred()); taskSummary.setAttachmentSummaries( diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/ObjectReferenceRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/ObjectReferenceRepresentationModel.java index ced808f8e..fd2cacd99 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/ObjectReferenceRepresentationModel.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/ObjectReferenceRepresentationModel.java @@ -7,6 +7,9 @@ public class ObjectReferenceRepresentationModel /** Unique ID. */ private String id; + + /** Task Id. */ + private String taskId; /** The company the referenced primary object belongs to. */ private String company; /** The (kind of) system, the referenced primary object resides in (e.g. SAP, MySystem A, ...). */ @@ -26,6 +29,14 @@ public class ObjectReferenceRepresentationModel this.id = id; } + public String getTaskId() { + return taskId; + } + + public void setTaskId(String taskId) { + this.taskId = taskId; + } + public String getCompany() { return company; } diff --git a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/TaskSummaryRepresentationModel.java b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/TaskSummaryRepresentationModel.java index 76ab26941..e5e0298dc 100644 --- a/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/TaskSummaryRepresentationModel.java +++ b/rest/taskana-rest-spring/src/main/java/pro/taskana/task/rest/models/TaskSummaryRepresentationModel.java @@ -106,6 +106,8 @@ public class TaskSummaryRepresentationModel protected String custom15; /** A custom property with name "16". */ protected String custom16; + /** Secondary object references of the task. */ + protected List secondaryObjectReferences = new ArrayList<>(); /** The attachment summaries of this task. */ private List attachmentSummaries = new ArrayList<>(); @@ -286,6 +288,15 @@ public class TaskSummaryRepresentationModel this.primaryObjRef = primaryObjRef; } + public List getSecondaryObjectReferences() { + return secondaryObjectReferences; + } + + public void setSecondaryObjectReferences( + List secondaryObjectReferences) { + this.secondaryObjectReferences = secondaryObjectReferences; + } + public boolean isRead() { return isRead; } diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java index 1602f9988..917eefccb 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerIntTest.java @@ -239,6 +239,51 @@ class TaskControllerIntTest { assertThat(response.getBody().getContent()).hasSize(4); } + @Test + void should_ReturnAllTasks_For_ProvidedSecondaryObjectReferenceByTypeAndValue() throws Exception { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?sor=" + + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Value2\"}", "UTF-8"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(2); + } + + @Test + void should_ReturnAllTasks_For_ProvidedSecondaryObjectReferenceByCompany() throws Exception { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?sor=" + + URLEncoder.encode("{\"company\":\"Company3\"}", "UTF-8"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(1); + } + + @Test + void should_ReturnNoTasks_For_ProvidedNonexistentSecondaryObjectReference() throws Exception { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + + "?sor=" + + URLEncoder.encode("{\"type\":\"Type2\",\"value\":\"Quatsch\"}", "UTF-8"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + assertThat(response.getBody()).isNotNull(); + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).isEmpty(); + } + @Test void should_ReturnAllTasksByWildcardSearch_For_ProvidedSearchValue() { String url = @@ -579,6 +624,89 @@ class TaskControllerIntTest { assertThat(repModel.getAttachments()).isNotEmpty(); } + @Test + void should_NotGetEmptyObjectReferencesList_When_GettingTaskWithObjectReferences() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS_ID, "TKI:000000000000000000000000000000000001"); + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_MODEL_TYPE); + + TaskRepresentationModel repModel = response.getBody(); + assertThat(repModel).isNotNull(); + assertThat(repModel.getSecondaryObjectReferences()).isNotEmpty(); + } + + @Test + void should_ReturnFilteredTasks_WhenGettingTasksBySecondaryObjectReferenceValue() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-value=Value2"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(3); + } + + @Test + void should_ReturnFilteredTasks_WhenGettingTasksBySecondaryObjectReferenceTypeLike() { + String url = restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-type-like=Type"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(3); + } + + @Test + void should_ReturnFilteredTasks_WhenGettingTasksBySecondaryObjectReferenceValueAndCompany() { + String url = + restHelper.toUrl(RestEndpoints.URL_TASKS) + "?sor-value=Value2&&sor-company=Company1"; + HttpEntity auth = new HttpEntity<>(RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity response = + TEMPLATE.exchange(url, HttpMethod.GET, auth, TASK_SUMMARY_PAGE_MODEL_TYPE); + + assertThat(response.getBody()).isNotNull(); + assertThat((response.getBody()).getLink(IanaLinkRelations.SELF)).isNotNull(); + assertThat(response.getBody().getContent()).hasSize(1); + } + + @Test + void should_CreateAndDeleteTaskWithObjectReferences_WhenSpecifyingObjectReferences() { + TaskRepresentationModel taskRepresentationModel = getTaskResourceSample(); + ObjectReferenceRepresentationModel obj0 = getSampleSecondaryObjectReference("0"); + obj0.setTaskId(taskRepresentationModel.getTaskId()); + ObjectReferenceRepresentationModel obj1 = getSampleSecondaryObjectReference("1"); + obj1.setTaskId(taskRepresentationModel.getTaskId()); + List secondaryObjectReferences = List.of(obj0, obj1); + taskRepresentationModel.setSecondaryObjectReferences(secondaryObjectReferences); + + String url = restHelper.toUrl(RestEndpoints.URL_TASKS); + HttpEntity auth = + new HttpEntity<>(taskRepresentationModel, RestHelper.generateHeadersForUser("teamlead-1")); + + ResponseEntity responseCreate = + TEMPLATE.exchange(url, HttpMethod.POST, auth, TASK_MODEL_TYPE); + assertThat(responseCreate.getStatusCode()).isEqualTo(HttpStatus.CREATED); + assertThat(responseCreate.getBody()).isNotNull(); + String taskIdOfCreatedTask = responseCreate.getBody().getTaskId(); + + String url2 = restHelper.toUrl(RestEndpoints.URL_TASKS_ID, taskIdOfCreatedTask); + HttpEntity auth2 = new HttpEntity<>(RestHelper.generateHeadersForUser("admin")); + + ResponseEntity responseDeleted = + TEMPLATE.exchange( + url2, HttpMethod.DELETE, auth2, ParameterizedTypeReference.forType(Void.class)); + assertThat(responseDeleted.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT); + } + @Test void should_ReturnReceivedDate_When_GettingTask() { String url = @@ -1029,4 +1157,14 @@ class TaskControllerIntTest { taskRepresentationModel.setPrimaryObjRef(objectReference); return taskRepresentationModel; } + + private ObjectReferenceRepresentationModel getSampleSecondaryObjectReference(String suffix) { + ObjectReferenceRepresentationModel objectReference = new ObjectReferenceRepresentationModel(); + objectReference.setCompany("SecondaryCompany" + suffix); + objectReference.setSystem("SecondarySystem" + suffix); + objectReference.setSystemInstance("SecondaryInstance" + suffix); + objectReference.setType("SecondaryType" + suffix); + objectReference.setValue("0000000" + suffix); + return objectReference; + } } diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java index 7258c67a4..d507e5940 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/TaskControllerRestDocTest.java @@ -16,8 +16,8 @@ import pro.taskana.common.test.rest.RestHelper; import pro.taskana.common.test.security.JaasExtension; import pro.taskana.common.test.security.WithAccessId; import pro.taskana.task.api.TaskService; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.rest.assembler.TaskRepresentationModelAssembler; import pro.taskana.task.rest.models.TaskRepresentationModel; @@ -106,7 +106,7 @@ class TaskControllerRestDocTest extends BaseRestDocTest { @Test void createTaskDocTest() throws Exception { final Task task = taskService.newTask("WBI:100000000000000000000000000000000004"); - ObjectReference objectReference = new ObjectReference(); + ObjectReferenceImpl objectReference = new ObjectReferenceImpl(); objectReference.setCompany("MyCompany1"); objectReference.setSystem("MySystem1"); objectReference.setSystemInstance("MyInstance1"); @@ -114,6 +114,7 @@ class TaskControllerRestDocTest extends BaseRestDocTest { objectReference.setValue("00000001"); task.setPrimaryObjRef(objectReference); task.setClassificationKey("L11010"); + task.addSecondaryObjectReference("company", "system", "systemInstance", "type", "value"); TaskRepresentationModel repModel = assembler.toModel(task); mockMvc .perform(post(RestEndpoints.URL_TASKS).content(objectMapper.writeValueAsString(repModel))) diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/AttachmentRepresentationModelAssemblerTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/AttachmentRepresentationModelAssemblerTest.java index 5719f1432..1fdb4d1b1 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/AttachmentRepresentationModelAssemblerTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/AttachmentRepresentationModelAssemblerTest.java @@ -13,8 +13,8 @@ import pro.taskana.classification.rest.models.ClassificationSummaryRepresentatio import pro.taskana.common.test.rest.TaskanaSpringBootTest; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.models.Attachment; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.internal.models.AttachmentImpl; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.rest.models.AttachmentRepresentationModel; import pro.taskana.task.rest.models.ObjectReferenceRepresentationModel; @@ -64,7 +64,7 @@ class AttachmentRepresentationModelAssemblerTest { @Test void should_ReturnRepresentationModel_When_ConvertingEntityToRepresentationModel() { AttachmentImpl attachment = (AttachmentImpl) taskService.newAttachment(); - ObjectReference reference = new ObjectReference(); + ObjectReferenceImpl reference = new ObjectReferenceImpl(); ClassificationSummary summary = classService.newClassification("ckey", "cdomain", "MANUAL").asSummary(); reference.setId("abc"); @@ -87,7 +87,7 @@ class AttachmentRepresentationModelAssemblerTest { @Test void should_Equal_When_ComparingEntityWithConvertedEntity() { AttachmentImpl attachment = (AttachmentImpl) taskService.newAttachment(); - ObjectReference reference = new ObjectReference(); + ObjectReferenceImpl reference = new ObjectReferenceImpl(); ClassificationSummary summary = classService.newClassification("ckey", "cdomain", "MANUAL").asSummary(); reference.setId("abc"); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/AttachmentSummaryRepresentationModelAssemblerTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/AttachmentSummaryRepresentationModelAssemblerTest.java index 21be712ec..40116646e 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/AttachmentSummaryRepresentationModelAssemblerTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/AttachmentSummaryRepresentationModelAssemblerTest.java @@ -12,8 +12,8 @@ import pro.taskana.classification.rest.models.ClassificationSummaryRepresentatio import pro.taskana.common.test.rest.TaskanaSpringBootTest; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.models.AttachmentSummary; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.internal.models.AttachmentSummaryImpl; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.rest.models.AttachmentSummaryRepresentationModel; import pro.taskana.task.rest.models.ObjectReferenceRepresentationModel; @@ -63,7 +63,7 @@ class AttachmentSummaryRepresentationModelAssemblerTest { void should_ReturnRepresentationModel_When_ConvertingEntityToRepresentationModel() { AttachmentSummaryImpl attachment = (AttachmentSummaryImpl) taskService.newAttachment().asSummary(); - ObjectReference reference = new ObjectReference(); + ObjectReferenceImpl reference = new ObjectReferenceImpl(); ClassificationSummary summary = classService.newClassification("ckey", "cdomain", "MANUAL").asSummary(); reference.setId("abc"); @@ -86,7 +86,7 @@ class AttachmentSummaryRepresentationModelAssemblerTest { void should_Equal_When_ComparingEntityWithConvertedEntity() { AttachmentSummaryImpl attachment = (AttachmentSummaryImpl) taskService.newAttachment().asSummary(); - ObjectReference reference = new ObjectReference(); + ObjectReferenceImpl reference = new ObjectReferenceImpl(); ClassificationSummary summary = classService.newClassification("ckey", "cdomain", "MANUAL").asSummary(); reference.setId("abc"); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/ObjectReferenceRepresentationModelAssemblerTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/ObjectReferenceRepresentationModelAssemblerTest.java index e010610e2..b7e3174ba 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/ObjectReferenceRepresentationModelAssemblerTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/ObjectReferenceRepresentationModelAssemblerTest.java @@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired; import pro.taskana.common.test.rest.TaskanaSpringBootTest; import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.rest.models.ObjectReferenceRepresentationModel; @TaskanaSpringBootTest @@ -37,7 +38,7 @@ class ObjectReferenceRepresentationModelAssemblerTest { @Test void should_ReturnRepresentationModel_When_ConvertingEntityToRepresentationModel() { - ObjectReference entity = new ObjectReference(); + ObjectReferenceImpl entity = new ObjectReferenceImpl(); entity.setId("id"); entity.setValue("value"); entity.setType("type"); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssemblerTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssemblerTest.java index 9017219f8..d3898d088 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssemblerTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskRepresentationModelAssemblerTest.java @@ -18,9 +18,9 @@ import pro.taskana.task.api.TaskCustomField; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.models.Attachment; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.Task; import pro.taskana.task.internal.models.AttachmentImpl; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskImpl; import pro.taskana.task.rest.models.AttachmentRepresentationModel; import pro.taskana.task.rest.models.ObjectReferenceRepresentationModel; @@ -152,7 +152,7 @@ class TaskRepresentationModelAssemblerTest { void should_ReturnRepresentationModel_When_ConvertingEntityToRepresentationModel() throws Exception { // given - ObjectReference primaryObjRef = new ObjectReference(); + ObjectReferenceImpl primaryObjRef = new ObjectReferenceImpl(); primaryObjRef.setId("abc"); final Workbasket workbasket = workbasketService.newWorkbasket("key", "domain"); ClassificationSummary classification = @@ -215,7 +215,7 @@ class TaskRepresentationModelAssemblerTest { @Test void should_Equal_When_ComparingEntityWithConvertedEntity() throws InvalidArgumentException { // given - ObjectReference primaryObjRef = new ObjectReference(); + ObjectReferenceImpl primaryObjRef = new ObjectReferenceImpl(); primaryObjRef.setId("abc"); final WorkbasketSummary workbasket = workbasketService.newWorkbasket("key", "domain").asSummary(); diff --git a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskSummaryRepresentationModelAssemblerTest.java b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskSummaryRepresentationModelAssemblerTest.java index fa419b54d..36c988592 100644 --- a/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskSummaryRepresentationModelAssemblerTest.java +++ b/rest/taskana-rest-spring/src/test/java/pro/taskana/task/rest/assembler/TaskSummaryRepresentationModelAssemblerTest.java @@ -30,9 +30,9 @@ import pro.taskana.common.test.rest.TaskanaSpringBootTest; import pro.taskana.task.api.TaskService; import pro.taskana.task.api.TaskState; import pro.taskana.task.api.models.AttachmentSummary; -import pro.taskana.task.api.models.ObjectReference; import pro.taskana.task.api.models.TaskSummary; import pro.taskana.task.internal.models.AttachmentSummaryImpl; +import pro.taskana.task.internal.models.ObjectReferenceImpl; import pro.taskana.task.internal.models.TaskSummaryImpl; import pro.taskana.task.rest.models.AttachmentRepresentationModel; import pro.taskana.task.rest.models.AttachmentSummaryRepresentationModel; @@ -66,7 +66,7 @@ class TaskSummaryRepresentationModelAssemblerTest { @Test void should_ReturnRepresentationModel_When_ConvertingEntityToRepresentationModel() throws Exception { - ObjectReference primaryObjRef = new ObjectReference(); + ObjectReferenceImpl primaryObjRef = new ObjectReferenceImpl(); primaryObjRef.setId("abc"); ClassificationSummary classification = this.classificationService.newClassification("ckey", "cdomain", "MANUAL").asSummary(); @@ -222,7 +222,7 @@ class TaskSummaryRepresentationModelAssemblerTest { @Test void should_Equal_When_ComparingEntityWithConvertedEntity() { // given - ObjectReference primaryObjRef = new ObjectReference(); + ObjectReferenceImpl primaryObjRef = new ObjectReferenceImpl(); primaryObjRef.setId("abc"); final WorkbasketSummary workbasket = workbasketService.newWorkbasket("key", "domain").asSummary(); @@ -335,7 +335,7 @@ class TaskSummaryRepresentationModelAssemblerTest { private static void testEqualityAttachments( List attachmentSummaries, List resources) { - assertThat(attachmentSummaries.size()).isEqualTo(resources.size()); + assertThat(attachmentSummaries).hasSameSizeAs(resources); for (int i = 0; i < resources.size(); ++i) { AttachmentSummaryRepresentationModel resource = resources.get(i); diff --git a/routing/taskana-spi-routing-dmn-router/src/test/java/pro/taskana/AbstractAccTest.java b/routing/taskana-spi-routing-dmn-router/src/test/java/pro/taskana/AbstractAccTest.java index 3cc1d9ae9..cfa919fd2 100644 --- a/routing/taskana-spi-routing-dmn-router/src/test/java/pro/taskana/AbstractAccTest.java +++ b/routing/taskana-spi-routing-dmn-router/src/test/java/pro/taskana/AbstractAccTest.java @@ -10,6 +10,7 @@ import pro.taskana.common.internal.configuration.DbSchemaCreator; import pro.taskana.common.test.config.DataSourceGenerator; import pro.taskana.sampledata.SampleDataGenerator; import pro.taskana.task.api.models.ObjectReference; +import pro.taskana.task.internal.models.ObjectReferenceImpl; public abstract class AbstractAccTest { @@ -45,7 +46,7 @@ public abstract class AbstractAccTest { protected ObjectReference createObjectReference( String company, String system, String systemInstance, String type, String value) { - ObjectReference objectReference = new ObjectReference(); + ObjectReferenceImpl objectReference = new ObjectReferenceImpl(); objectReference.setCompany(company); objectReference.setSystem(system); objectReference.setSystemInstance(systemInstance); diff --git a/web/src/app/workplace/components/task-details/task-details.component.ts b/web/src/app/workplace/components/task-details/task-details.component.ts index 3ae244efa..8d5384b90 100644 --- a/web/src/app/workplace/components/task-details/task-details.component.ts +++ b/web/src/app/workplace/components/task-details/task-details.component.ts @@ -6,12 +6,12 @@ import { TaskService } from 'app/workplace/services/task.service'; import { Task } from 'app/workplace/models/task'; import { RequestInProgressService } from 'app/shared/services/request-in-progress/request-in-progress.service'; import { TaskanaDate } from 'app/shared/util/taskana.date'; -import { ObjectReference } from 'app/workplace/models/object-reference'; import { Workbasket } from 'app/shared/models/workbasket'; import { WorkplaceService } from 'app/workplace/services/workplace.service'; import { MasterAndDetailService } from 'app/shared/services/master-and-detail/master-and-detail.service'; import { NotificationService } from '../../../shared/services/notifications/notification.service'; import { take, takeUntil } from 'rxjs/operators'; +import { ObjectReference } from '../../models/object-reference'; @Component({ selector: 'taskana-task-details', @@ -186,7 +186,10 @@ export class TaskDetailsComponent implements OnInit, OnDestroy { this.task = task; this.taskService.selectTask(this.task); this.taskService.publishUpdatedTask(task); - this.router.navigate([`../${task.taskId}`], { relativeTo: this.route, queryParamsHandling: 'merge' }); + this.router.navigate([`../${task.taskId}`], { + relativeTo: this.route, + queryParamsHandling: 'merge' + }); }, () => { this.requestInProgressService.setRequestInProgress(false); diff --git a/web/src/app/workplace/models/task.ts b/web/src/app/workplace/models/task.ts index 379263811..7fd3afdc5 100644 --- a/web/src/app/workplace/models/task.ts +++ b/web/src/app/workplace/models/task.ts @@ -5,7 +5,7 @@ import { ClassificationSummary } from '../../shared/models/classification-summar export class Task { constructor( public taskId: string, - public primaryObjRef: ObjectReference = new ObjectReference(), + public primaryObjRef?: ObjectReference, public workbasketSummary?: Workbasket, public classificationSummary?: ClassificationSummary, public businessProcessId?: string,