diff --git a/build-system/pom.xml b/build-system/pom.xml index 343ead78135..c922ac21273 100644 --- a/build-system/pom.xml +++ b/build-system/pom.xml @@ -74,8 +74,8 @@ 5.1.31 7.1.0 2.4.0 - 5.17.0 - 5.17.0 + 5.19.0.2 + 5.19.0.2 1.3 2.0.1 1.4.3.0-SNAPSHOT @@ -294,6 +294,11 @@ commons-pool 1.5.6 + + org.jetbrains + annotations-java5 + 15.0 + javax.annotation jsr250-api diff --git a/config/sql/midpoint/3.4/h2/h2-3.4.sql b/config/sql/midpoint/3.4/h2/h2-3.4.sql index 9e1951d7d48..0b6f61bdf60 100644 --- a/config/sql/midpoint/3.4/h2/h2-3.4.sql +++ b/config/sql/midpoint/3.4/h2/h2-3.4.sql @@ -621,6 +621,18 @@ CREATE TABLE m_task ( taskIdentifier VARCHAR(255), threadStopAction INTEGER, waitingReason INTEGER, + wfEndTimestamp TIMESTAMP, + wfObjectRef_relation VARCHAR(157), + wfObjectRef_targetOid VARCHAR(36), + wfObjectRef_type INTEGER, + wfProcessInstanceId VARCHAR(255), + wfRequesterRef_relation VARCHAR(157), + wfRequesterRef_targetOid VARCHAR(36), + wfRequesterRef_type INTEGER, + wfStartTimestamp TIMESTAMP, + wfTargetRef_relation VARCHAR(157), + wfTargetRef_targetOid VARCHAR(36), + wfTargetRef_type INTEGER, oid VARCHAR(36) NOT NULL, PRIMARY KEY (oid) ); @@ -837,6 +849,18 @@ ADD CONSTRAINT uc_system_configuration_name UNIQUE (name_norm); CREATE INDEX iParent ON m_task (parent); +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + CREATE INDEX iTriggerTimestamp ON m_trigger (timestampValue); ALTER TABLE m_user diff --git a/config/sql/midpoint/3.4/h2/h2-upgrade-3.3-3.4.sql b/config/sql/midpoint/3.4/h2/h2-upgrade-3.3-3.4.sql index 662aff41f9c..1f64982636f 100644 --- a/config/sql/midpoint/3.4/h2/h2-upgrade-3.3-3.4.sql +++ b/config/sql/midpoint/3.4/h2/h2-upgrade-3.3-3.4.sql @@ -1,3 +1,28 @@ +ALTER TABLE m_task ADD wfEndTimestamp TIMESTAMP; +ALTER TABLE m_task ADD wfObjectRef_relation VARCHAR(157); +ALTER TABLE m_task ADD wfObjectRef_targetOid VARCHAR(36); +ALTER TABLE m_task ADD wfObjectRef_type INTEGER; +ALTER TABLE m_task ADD wfProcessInstanceId VARCHAR(255); +ALTER TABLE m_task ADD wfRequesterRef_relation VARCHAR(157); +ALTER TABLE m_task ADD wfRequesterRef_targetOid VARCHAR(36); +ALTER TABLE m_task ADD wfRequesterRef_type INTEGER; +ALTER TABLE m_task ADD wfStartTimestamp TIMESTAMP; +ALTER TABLE m_task ADD wfTargetRef_relation VARCHAR(157); +ALTER TABLE m_task ADD wfTargetRef_targetOid VARCHAR(36); +ALTER TABLE m_task ADD wfTargetRef_type INTEGER; + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + ALTER TABLE m_abstract_role ADD ownerRef_relation VARCHAR(157); ALTER TABLE m_abstract_role ADD ownerRef_targetOid VARCHAR(36); ALTER TABLE m_abstract_role ADD ownerRef_type INTEGER; diff --git a/config/sql/midpoint/3.4/h2/h2-upgrade-3.4-SNAPSHOT-3.sql b/config/sql/midpoint/3.4/h2/h2-upgrade-3.4-SNAPSHOT-3.sql new file mode 100644 index 00000000000..cffc2ec30fe --- /dev/null +++ b/config/sql/midpoint/3.4/h2/h2-upgrade-3.4-SNAPSHOT-3.sql @@ -0,0 +1,25 @@ +ALTER TABLE m_task ADD wfEndTimestamp TIMESTAMP; +ALTER TABLE m_task ADD wfObjectRef_relation VARCHAR(157); +ALTER TABLE m_task ADD wfObjectRef_targetOid VARCHAR(36); +ALTER TABLE m_task ADD wfObjectRef_type INTEGER; +ALTER TABLE m_task ADD wfProcessInstanceId VARCHAR(255); +ALTER TABLE m_task ADD wfRequesterRef_relation VARCHAR(157); +ALTER TABLE m_task ADD wfRequesterRef_targetOid VARCHAR(36); +ALTER TABLE m_task ADD wfRequesterRef_type INTEGER; +ALTER TABLE m_task ADD wfStartTimestamp TIMESTAMP; +ALTER TABLE m_task ADD wfTargetRef_relation VARCHAR(157); +ALTER TABLE m_task ADD wfTargetRef_targetOid VARCHAR(36); +ALTER TABLE m_task ADD wfTargetRef_type INTEGER; + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + diff --git a/config/sql/midpoint/3.4/mysql/mysql-3.4.sql b/config/sql/midpoint/3.4/mysql/mysql-3.4.sql index 37bf1b8fe24..25cc8126d40 100644 --- a/config/sql/midpoint/3.4/mysql/mysql-3.4.sql +++ b/config/sql/midpoint/3.4/mysql/mysql-3.4.sql @@ -775,6 +775,18 @@ CREATE TABLE m_task ( taskIdentifier VARCHAR(255), threadStopAction INTEGER, waitingReason INTEGER, + wfEndTimestamp DATETIME(6), + wfObjectRef_relation VARCHAR(157), + wfObjectRef_targetOid VARCHAR(36), + wfObjectRef_type INTEGER, + wfProcessInstanceId VARCHAR(255), + wfRequesterRef_relation VARCHAR(157), + wfRequesterRef_targetOid VARCHAR(36), + wfRequesterRef_type INTEGER, + wfStartTimestamp DATETIME(6), + wfTargetRef_relation VARCHAR(157), + wfTargetRef_targetOid VARCHAR(36), + wfTargetRef_type INTEGER, oid VARCHAR(36) NOT NULL, PRIMARY KEY (oid) ) @@ -1017,6 +1029,18 @@ ADD CONSTRAINT uc_system_configuration_name UNIQUE (name_norm); CREATE INDEX iParent ON m_task (parent); +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + CREATE INDEX iTriggerTimestamp ON m_trigger (timestampValue); ALTER TABLE m_user diff --git a/config/sql/midpoint/3.4/mysql/mysql-upgrade-3.3-3.4.sql b/config/sql/midpoint/3.4/mysql/mysql-upgrade-3.3-3.4.sql index 1d8e037472f..b2c3b55f529 100644 --- a/config/sql/midpoint/3.4/mysql/mysql-upgrade-3.3-3.4.sql +++ b/config/sql/midpoint/3.4/mysql/mysql-upgrade-3.3-3.4.sql @@ -1,3 +1,29 @@ +ALTER TABLE m_task + ADD wfEndTimestamp DATETIME(6), + ADD wfObjectRef_relation VARCHAR(157), + ADD wfObjectRef_targetOid VARCHAR(36), + ADD wfObjectRef_type INTEGER, + ADD wfProcessInstanceId VARCHAR(255), + ADD wfRequesterRef_relation VARCHAR(157), + ADD wfRequesterRef_targetOid VARCHAR(36), + ADD wfRequesterRef_type INTEGER, + ADD wfStartTimestamp DATETIME(6), + ADD wfTargetRef_relation VARCHAR(157), + ADD wfTargetRef_targetOid VARCHAR(36), + ADD wfTargetRef_type INTEGER; + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + ALTER TABLE m_abstract_role ADD ownerRef_relation VARCHAR(157), ADD ownerRef_targetOid VARCHAR(36), diff --git a/config/sql/midpoint/3.4/mysql/mysql-upgrade-3.4-SNAPSHOT-3.sql b/config/sql/midpoint/3.4/mysql/mysql-upgrade-3.4-SNAPSHOT-3.sql new file mode 100644 index 00000000000..417790144dd --- /dev/null +++ b/config/sql/midpoint/3.4/mysql/mysql-upgrade-3.4-SNAPSHOT-3.sql @@ -0,0 +1,25 @@ +ALTER TABLE m_task + ADD wfEndTimestamp DATETIME(6), + ADD wfObjectRef_relation VARCHAR(157), + ADD wfObjectRef_targetOid VARCHAR(36), + ADD wfObjectRef_type INTEGER, + ADD wfProcessInstanceId VARCHAR(255), + ADD wfRequesterRef_relation VARCHAR(157), + ADD wfRequesterRef_targetOid VARCHAR(36), + ADD wfRequesterRef_type INTEGER, + ADD wfStartTimestamp DATETIME(6), + ADD wfTargetRef_relation VARCHAR(157), + ADD wfTargetRef_targetOid VARCHAR(36), + ADD wfTargetRef_type INTEGER; + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); diff --git a/config/sql/midpoint/3.4/oracle/oracle-3.4.sql b/config/sql/midpoint/3.4/oracle/oracle-3.4.sql index 23a3ccbd69b..a591fd900db 100644 --- a/config/sql/midpoint/3.4/oracle/oracle-3.4.sql +++ b/config/sql/midpoint/3.4/oracle/oracle-3.4.sql @@ -631,6 +631,18 @@ CREATE TABLE m_task ( taskIdentifier VARCHAR2(255 CHAR), threadStopAction NUMBER(10, 0), waitingReason NUMBER(10, 0), + wfEndTimestamp TIMESTAMP, + wfObjectRef_relation VARCHAR2(157 CHAR), + wfObjectRef_targetOid VARCHAR2(36 CHAR), + wfObjectRef_type NUMBER(10, 0), + wfProcessInstanceId VARCHAR2(255 CHAR), + wfRequesterRef_relation VARCHAR2(157 CHAR), + wfRequesterRef_targetOid VARCHAR2(36 CHAR), + wfRequesterRef_type NUMBER(10, 0), + wfStartTimestamp TIMESTAMP, + wfTargetRef_relation VARCHAR2(157 CHAR), + wfTargetRef_targetOid VARCHAR2(36 CHAR), + wfTargetRef_type NUMBER(10, 0), oid VARCHAR2(36 CHAR) NOT NULL, PRIMARY KEY (oid) ) INITRANS 30; @@ -847,6 +859,18 @@ ADD CONSTRAINT uc_system_configuration_name UNIQUE (name_norm) INITRANS 30; CREATE INDEX iParent ON m_task (parent) INITRANS 30; +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId) INITRANS 30; + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp) INITRANS 30; + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp) INITRANS 30; + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid) INITRANS 30; + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid) INITRANS 30; + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid) INITRANS 30; + CREATE INDEX iTriggerTimestamp ON m_trigger (timestampValue) INITRANS 30; ALTER TABLE m_user diff --git a/config/sql/midpoint/3.4/oracle/oracle-upgrade-3.3-3.4.sql b/config/sql/midpoint/3.4/oracle/oracle-upgrade-3.3-3.4.sql index bd3760bd411..4b9755b5449 100644 --- a/config/sql/midpoint/3.4/oracle/oracle-upgrade-3.3-3.4.sql +++ b/config/sql/midpoint/3.4/oracle/oracle-upgrade-3.3-3.4.sql @@ -1,3 +1,30 @@ +ALTER TABLE m_task ADD ( + wfEndTimestamp TIMESTAMP, + wfObjectRef_relation VARCHAR2(157 CHAR), + wfObjectRef_targetOid VARCHAR2(36 CHAR), + wfObjectRef_type NUMBER(10, 0), + wfProcessInstanceId VARCHAR2(255 CHAR), + wfRequesterRef_relation VARCHAR2(157 CHAR), + wfRequesterRef_targetOid VARCHAR2(36 CHAR), + wfRequesterRef_type NUMBER(10, 0), + wfStartTimestamp TIMESTAMP, + wfTargetRef_relation VARCHAR2(157 CHAR), + wfTargetRef_targetOid VARCHAR2(36 CHAR), + wfTargetRef_type NUMBER(10, 0) +); + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId) INITRANS 30; + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp) INITRANS 30; + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp) INITRANS 30; + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid) INITRANS 30; + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid) INITRANS 30; + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid) INITRANS 30; + ALTER TABLE m_abstract_role ADD ( ownerRef_relation VARCHAR2(157 CHAR), ownerRef_targetOid VARCHAR2(36 CHAR), diff --git a/config/sql/midpoint/3.4/oracle/oracle-upgrade-3.4-SNAPSHOT-3.sql b/config/sql/midpoint/3.4/oracle/oracle-upgrade-3.4-SNAPSHOT-3.sql new file mode 100644 index 00000000000..6392fbe73b1 --- /dev/null +++ b/config/sql/midpoint/3.4/oracle/oracle-upgrade-3.4-SNAPSHOT-3.sql @@ -0,0 +1,26 @@ +ALTER TABLE m_task ADD ( + wfEndTimestamp TIMESTAMP, + wfObjectRef_relation VARCHAR2(157 CHAR), + wfObjectRef_targetOid VARCHAR2(36 CHAR), + wfObjectRef_type NUMBER(10, 0), + wfProcessInstanceId VARCHAR2(255 CHAR), + wfRequesterRef_relation VARCHAR2(157 CHAR), + wfRequesterRef_targetOid VARCHAR2(36 CHAR), + wfRequesterRef_type NUMBER(10, 0), + wfStartTimestamp TIMESTAMP, + wfTargetRef_relation VARCHAR2(157 CHAR), + wfTargetRef_targetOid VARCHAR2(36 CHAR), + wfTargetRef_type NUMBER(10, 0) +); + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId) INITRANS 30; + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp) INITRANS 30; + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp) INITRANS 30; + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid) INITRANS 30; + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid) INITRANS 30; + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid) INITRANS 30; diff --git a/config/sql/midpoint/3.4/postgresql/postgresql-3.4.sql b/config/sql/midpoint/3.4/postgresql/postgresql-3.4.sql index 8bc282e942a..a83481e4d81 100644 --- a/config/sql/midpoint/3.4/postgresql/postgresql-3.4.sql +++ b/config/sql/midpoint/3.4/postgresql/postgresql-3.4.sql @@ -621,6 +621,18 @@ CREATE TABLE m_task ( taskIdentifier VARCHAR(255), threadStopAction INT4, waitingReason INT4, + wfEndTimestamp TIMESTAMP, + wfObjectRef_relation VARCHAR(157), + wfObjectRef_targetOid VARCHAR(36), + wfObjectRef_type INT4, + wfProcessInstanceId VARCHAR(255), + wfRequesterRef_relation VARCHAR(157), + wfRequesterRef_targetOid VARCHAR(36), + wfRequesterRef_type INT4, + wfStartTimestamp TIMESTAMP, + wfTargetRef_relation VARCHAR(157), + wfTargetRef_targetOid VARCHAR(36), + wfTargetRef_type INT4, oid VARCHAR(36) NOT NULL, PRIMARY KEY (oid) ); @@ -837,6 +849,18 @@ ADD CONSTRAINT uc_system_configuration_name UNIQUE (name_norm); CREATE INDEX iParent ON m_task (parent); +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + CREATE INDEX iTriggerTimestamp ON m_trigger (timestampValue); ALTER TABLE m_user diff --git a/config/sql/midpoint/3.4/postgresql/postgresql-upgrade-3.3-3.4.sql b/config/sql/midpoint/3.4/postgresql/postgresql-upgrade-3.3-3.4.sql index 75ad030a052..06e068e55f8 100644 --- a/config/sql/midpoint/3.4/postgresql/postgresql-upgrade-3.3-3.4.sql +++ b/config/sql/midpoint/3.4/postgresql/postgresql-upgrade-3.3-3.4.sql @@ -1,3 +1,29 @@ +ALTER TABLE m_task + ADD wfEndTimestamp TIMESTAMP, + ADD wfObjectRef_relation VARCHAR(157), + ADD wfObjectRef_targetOid VARCHAR(36), + ADD wfObjectRef_type INT4, + ADD wfProcessInstanceId VARCHAR(255), + ADD wfRequesterRef_relation VARCHAR(157), + ADD wfRequesterRef_targetOid VARCHAR(36), + ADD wfRequesterRef_type INT4, + ADD wfStartTimestamp TIMESTAMP, + ADD wfTargetRef_relation VARCHAR(157), + ADD wfTargetRef_targetOid VARCHAR(36), + ADD wfTargetRef_type INT4; + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + ALTER TABLE m_abstract_role ADD ownerRef_relation VARCHAR(157), ADD ownerRef_targetOid VARCHAR(36), diff --git a/config/sql/midpoint/3.4/postgresql/postgresql-upgrade-3.4-SNAPSHOT-3.sql b/config/sql/midpoint/3.4/postgresql/postgresql-upgrade-3.4-SNAPSHOT-3.sql new file mode 100644 index 00000000000..60548ade72f --- /dev/null +++ b/config/sql/midpoint/3.4/postgresql/postgresql-upgrade-3.4-SNAPSHOT-3.sql @@ -0,0 +1,26 @@ +ALTER TABLE m_task + ADD wfEndTimestamp TIMESTAMP, + ADD wfObjectRef_relation VARCHAR(157), + ADD wfObjectRef_targetOid VARCHAR(36), + ADD wfObjectRef_type INT4, + ADD wfProcessInstanceId VARCHAR(255), + ADD wfRequesterRef_relation VARCHAR(157), + ADD wfRequesterRef_targetOid VARCHAR(36), + ADD wfRequesterRef_type INT4, + ADD wfStartTimestamp TIMESTAMP, + ADD wfTargetRef_relation VARCHAR(157), + ADD wfTargetRef_targetOid VARCHAR(36), + ADD wfTargetRef_type INT4; + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + diff --git a/config/sql/midpoint/3.4/sqlserver/sqlserver-3.4.sql b/config/sql/midpoint/3.4/sqlserver/sqlserver-3.4.sql index 9eb3fc6b567..695a5fcef24 100644 --- a/config/sql/midpoint/3.4/sqlserver/sqlserver-3.4.sql +++ b/config/sql/midpoint/3.4/sqlserver/sqlserver-3.4.sql @@ -621,6 +621,18 @@ CREATE TABLE m_task ( taskIdentifier NVARCHAR(255) COLLATE database_default, threadStopAction INT, waitingReason INT, + wfEndTimestamp DATETIME2, + wfObjectRef_relation NVARCHAR(157) COLLATE database_default, + wfObjectRef_targetOid NVARCHAR(36) COLLATE database_default, + wfObjectRef_type INT, + wfProcessInstanceId NVARCHAR(255) COLLATE database_default, + wfRequesterRef_relation NVARCHAR(157) COLLATE database_default, + wfRequesterRef_targetOid NVARCHAR(36) COLLATE database_default, + wfRequesterRef_type INT, + wfStartTimestamp DATETIME2, + wfTargetRef_relation NVARCHAR(157) COLLATE database_default, + wfTargetRef_targetOid NVARCHAR(36) COLLATE database_default, + wfTargetRef_type INT, oid NVARCHAR(36) COLLATE database_default NOT NULL, PRIMARY KEY (oid) ); @@ -837,6 +849,18 @@ ADD CONSTRAINT uc_system_configuration_name UNIQUE (name_norm); CREATE INDEX iParent ON m_task (parent); +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + CREATE INDEX iTriggerTimestamp ON m_trigger (timestampValue); ALTER TABLE m_user diff --git a/config/sql/midpoint/3.4/sqlserver/sqlserver-upgrade-3.3-3.4.sql b/config/sql/midpoint/3.4/sqlserver/sqlserver-upgrade-3.3-3.4.sql index 9a3b19dcfca..073a45030cd 100644 --- a/config/sql/midpoint/3.4/sqlserver/sqlserver-upgrade-3.3-3.4.sql +++ b/config/sql/midpoint/3.4/sqlserver/sqlserver-upgrade-3.3-3.4.sql @@ -1,3 +1,29 @@ +ALTER TABLE m_task ADD + wfEndTimestamp DATETIME2, + wfObjectRef_relation NVARCHAR(157) COLLATE database_default, + wfObjectRef_targetOid NVARCHAR(36) COLLATE database_default, + wfObjectRef_type INT, + wfProcessInstanceId NVARCHAR(255) COLLATE database_default, + wfRequesterRef_relation NVARCHAR(157) COLLATE database_default, + wfRequesterRef_targetOid NVARCHAR(36) COLLATE database_default, + wfRequesterRef_type INT, + wfStartTimestamp DATETIME2, + wfTargetRef_relation NVARCHAR(157) COLLATE database_default, + wfTargetRef_targetOid NVARCHAR(36) COLLATE database_default, + wfTargetRef_type INT; + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + ALTER TABLE m_abstract_role ADD ownerRef_relation NVARCHAR(157) COLLATE database_default, ownerRef_targetOid NVARCHAR(36) COLLATE database_default, diff --git a/config/sql/midpoint/3.4/sqlserver/sqlserver-upgrade-3.4-SNAPSHOT-3.sql b/config/sql/midpoint/3.4/sqlserver/sqlserver-upgrade-3.4-SNAPSHOT-3.sql new file mode 100644 index 00000000000..efa2deb3172 --- /dev/null +++ b/config/sql/midpoint/3.4/sqlserver/sqlserver-upgrade-3.4-SNAPSHOT-3.sql @@ -0,0 +1,26 @@ +ALTER TABLE m_task ADD + wfEndTimestamp DATETIME2, + wfObjectRef_relation NVARCHAR(157) COLLATE database_default, + wfObjectRef_targetOid NVARCHAR(36) COLLATE database_default, + wfObjectRef_type INT, + wfProcessInstanceId NVARCHAR(255) COLLATE database_default, + wfRequesterRef_relation NVARCHAR(157) COLLATE database_default, + wfRequesterRef_targetOid NVARCHAR(36) COLLATE database_default, + wfRequesterRef_type INT, + wfStartTimestamp DATETIME2, + wfTargetRef_relation NVARCHAR(157) COLLATE database_default, + wfTargetRef_targetOid NVARCHAR(36) COLLATE database_default, + wfTargetRef_type INT; + +CREATE INDEX iTaskWfProcessInstanceId ON m_task (wfProcessInstanceId); + +CREATE INDEX iTaskWfStartTimestamp ON m_task (wfStartTimestamp); + +CREATE INDEX iTaskWfEndTimestamp ON m_task (wfEndTimestamp); + +CREATE INDEX iTaskWfRequesterOid ON m_task (wfRequesterRef_targetOid); + +CREATE INDEX iTaskWfObjectOid ON m_task (wfObjectRef_targetOid); + +CREATE INDEX iTaskWfTargetOid ON m_task (wfTargetRef_targetOid); + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebComponentUtil.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebComponentUtil.java index 94f632a3b33..d629b9a0006 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebComponentUtil.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/gui/api/util/WebComponentUtil.java @@ -16,63 +16,43 @@ package com.evolveum.midpoint.gui.api.util; -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismContainerValue; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismProperty; -import com.evolveum.midpoint.prism.PrismPropertyValue; -import com.evolveum.midpoint.prism.crypto.EncryptionException; -import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.crypto.EncryptionException; +import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.PropertyDelta; -import com.evolveum.midpoint.prism.match.DistinguishedNameMatchingRule; -import com.evolveum.midpoint.prism.match.PolyStringNormMatchingRule; -import com.evolveum.midpoint.prism.match.PolyStringOrigMatchingRule; -import com.evolveum.midpoint.prism.match.PolyStringStrictMatchingRule; -import com.evolveum.midpoint.prism.match.StringIgnoreCaseMatchingRule; +import com.evolveum.midpoint.prism.match.*; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.ItemPathSegment; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.query.ObjectPaging; -import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.prism.xml.XsdTypeMapper; import com.evolveum.midpoint.schema.SchemaConstantsGenerated; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.task.api.TaskCategory; import com.evolveum.midpoint.util.DOMUtil; import com.evolveum.midpoint.util.DisplayableValue; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.security.api.Authorization; -import com.evolveum.midpoint.security.api.AuthorizationConstants; -import com.evolveum.midpoint.security.api.MidPointPrincipal; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskCategory; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.data.BaseSortableDataProvider; -import com.evolveum.midpoint.web.component.data.BoxedTablePanel; import com.evolveum.midpoint.web.component.data.Table; -import com.evolveum.midpoint.web.component.data.TablePanel; import com.evolveum.midpoint.web.component.input.DropDownChoicePanel; -import com.evolveum.midpoint.web.component.prism.ObjectWrapper; import com.evolveum.midpoint.web.component.util.Selectable; -import com.evolveum.midpoint.web.component.wf.processes.itemApproval.ItemApprovalPanel; import com.evolveum.midpoint.web.page.PageDialog; import com.evolveum.midpoint.web.page.admin.configuration.component.EmptyOnBlurAjaxFormUpdatingBehaviour; import com.evolveum.midpoint.web.page.admin.configuration.component.EmptyOnChangeAjaxFormUpdatingBehavior; -import com.evolveum.midpoint.web.page.admin.configuration.component.ObjectSelectionPanel; import com.evolveum.midpoint.web.security.MidPointApplication; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; -import com.sun.management.OperatingSystemMXBean; - import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.wicket.*; @@ -87,29 +67,20 @@ import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; -import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.StringResourceModel; import org.apache.wicket.request.IRequestHandler; import org.apache.wicket.util.visit.IVisit; import org.apache.wicket.util.visit.IVisitor; -import javax.management.*; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; - import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.RuntimeMXBean; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Locale; +import java.util.*; /** * Utility class containing miscellaneous methods used mostly in Wicket components. @@ -407,10 +378,12 @@ public static String getName(ObjectReferenceType ref) { if (ref == null) { return null; } - if (ref.getTargetName() != null) { return getOrigStringFromPoly(ref.getTargetName()); } + if (ref.asReferenceValue().getObject() != null) { + return getName(ref.asReferenceValue().getObject()); + } return ref.getOid(); } @@ -991,4 +964,17 @@ public static ItemPath joinPath(ItemPath path, ItemPath deltaPath) { return new ItemPath(newPath); } + + public static T getObjectFromReference(ObjectReferenceType ref, Class type) { + if (ref == null || ref.asReferenceValue().getObject() == null) { + return null; + } + Objectable object = ref.asReferenceValue().getObject().asObjectable(); + if (!type.isAssignableFrom(object.getClass())) { + throw new IllegalStateException("Got " + object.getClass() + " when expected " + type + ": " + ObjectTypeUtil.toShortString(ref, true)); + } + return (T) object; + } + + } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/BaseSortableDataProvider.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/BaseSortableDataProvider.java index a086d503472..067ee013e26 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/BaseSortableDataProvider.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/data/BaseSortableDataProvider.java @@ -22,9 +22,11 @@ import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.model.api.TaskService; import com.evolveum.midpoint.model.api.WorkflowService; +import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.query.OrderDirection; +import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.SchemaConstantsGenerated; import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.util.logging.Trace; @@ -83,11 +85,21 @@ protected ModelService getModel() { return application.getModel(); } + protected RepositoryService getRepositoryService() { + MidPointApplication application = (MidPointApplication) MidPointApplication.get(); + return application.getRepositoryService(); + } + protected TaskManager getTaskManager() { MidPointApplication application = (MidPointApplication) MidPointApplication.get(); return application.getTaskManager(); } + protected PrismContext getPrismContext() { + MidPointApplication application = (MidPointApplication) MidPointApplication.get(); + return application.getPrismContext(); + } + protected TaskService getTaskService() { MidPointApplication application = (MidPointApplication) MidPointApplication.get(); return application.getTaskService(); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/PasswordPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/PasswordPanel.html index ea50ece1afa..4fa1c64a126 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/PasswordPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/PasswordPanel.html @@ -17,10 +17,11 @@ - -
+ +
-
+
+
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/PasswordPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/PasswordPanel.java index 0a323faa10c..3db99e6e108 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/PasswordPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/input/PasswordPanel.java @@ -48,7 +48,10 @@ public class PasswordPanel extends InputPanel { private static final String ID_LINK_CONTAINER = "linkContainer"; private static final String ID_PASSWORD_SET = "passwordSet"; + private static final String ID_PASSWORD_REMOVE = "passwordRemove"; private static final String ID_CHANGE_PASSWORD_LINK = "changePasswordLink"; + private static final String ID_REMOVE_PASSWORD_LINK = "removePasswordLink"; + private static final String ID_REMOVE_BUTTON_CONTAINER = "removeButtonContainer"; private static final String ID_INPUT_CONTAINER = "inputContainer"; private static final String ID_PASSWORD_ONE = "password1"; private static final String ID_PASSWORD_TWO = "password2"; @@ -58,18 +61,18 @@ public class PasswordPanel extends InputPanel { private boolean passwordInputVisble; public PasswordPanel(String id, IModel model) { - this(id, model, false); + this(id, model, false, false); } - public PasswordPanel(String id, IModel model, boolean isReadOnly) { + public PasswordPanel(String id, IModel model, boolean isReadOnly, boolean showRemoveButton) { super(id); - initLayout(model, isReadOnly); + initLayout(model, isReadOnly, showRemoveButton); } - private void initLayout(IModel model, final boolean isReadOnly) { + private void initLayout(final IModel model, final boolean isReadOnly, boolean showRemoveButton) { setOutputMarkupId(true); - + passwordInputVisble = model.getObject() == null; // TODO: remove // LOGGER.trace("PASSWORD model: {}", model.getObject()); @@ -116,11 +119,16 @@ public boolean isVisible() { } }; inputContainer.setOutputMarkupId(true); + linkContainer.setOutputMarkupId(true); add(linkContainer); - Label passwordSetLabel = new Label(ID_PASSWORD_SET, new ResourceModel("passwordPanel.passwordSet")); + final Label passwordSetLabel = new Label(ID_PASSWORD_SET, new ResourceModel("passwordPanel.passwordSet")); linkContainer.add(passwordSetLabel); + final Label passwordRemoveLabel = new Label(ID_PASSWORD_REMOVE, new ResourceModel("passwordPanel.passwordRemoveLabel")); + passwordRemoveLabel.setVisible(false); + linkContainer.add(passwordRemoveLabel); + AjaxLink link = new AjaxLink(ID_CHANGE_PASSWORD_LINK) { @Override public void onClick(AjaxRequestTarget target) { @@ -142,7 +150,20 @@ public boolean isVisible() { link.setBody(new ResourceModel("passwordPanel.passwordChange")); link.setOutputMarkupId(true); linkContainer.add(link); - + + final WebMarkupContainer removeButtonContainer = new WebMarkupContainer(ID_REMOVE_BUTTON_CONTAINER); + AjaxLink removePassword = new AjaxLink(ID_REMOVE_PASSWORD_LINK) { + @Override + public void onClick(AjaxRequestTarget target) { + onRemovePassword(model, target); + } + + }; + removePassword.setVisible(showRemoveButton); + removePassword.setBody(new ResourceModel("passwordPanel.passwordRemove")); + removePassword.setOutputMarkupId(true); + removeButtonContainer.add(removePassword); + add(removeButtonContainer); } private void onLinkClick(AjaxRequestTarget target) { @@ -150,6 +171,18 @@ private void onLinkClick(AjaxRequestTarget target) { target.add(this); } + private void onRemovePassword(IModel model, AjaxRequestTarget target) { + get(ID_LINK_CONTAINER).get(ID_PASSWORD_SET).setVisible(false); + get(ID_LINK_CONTAINER).get(ID_PASSWORD_REMOVE).setVisible(true); + passwordInputVisble = false; + target.add(this); + + ProtectedStringType newValue = new ProtectedStringType(); + byte[] temp = new byte[0]; + newValue.setClearBytes(temp); + model.setObject(null); + } + @Override public List getFormComponents() { List list = new ArrayList(); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/model/operationStatus/ModelOperationStatusDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/model/operationStatus/ModelOperationStatusDto.java index 8d5465a6927..e12eff2c76a 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/model/operationStatus/ModelOperationStatusDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/model/operationStatus/ModelOperationStatusDto.java @@ -16,12 +16,26 @@ package com.evolveum.midpoint.web.component.model.operationStatus; +import com.evolveum.midpoint.model.api.ModelInteractionService; import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.api.context.ModelProjectionContext; import com.evolveum.midpoint.model.api.context.ModelState; +import com.evolveum.midpoint.model.api.visualizer.Scene; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.web.component.model.delta.DeltaDto; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.web.component.prism.show.WrapperScene; +import com.evolveum.midpoint.web.component.prism.show.SceneDto; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import static org.apache.commons.collections.CollectionUtils.addIgnoreNull; /** * @author mederly @@ -36,9 +50,9 @@ public class ModelOperationStatusDto implements Serializable { private ModelState state; private String focusType; private String focusName; - private DeltaDto primaryDelta; + private SceneDto primarySceneDto; - public ModelOperationStatusDto(ModelContext modelContext) { + public ModelOperationStatusDto(ModelContext modelContext, ModelInteractionService modelInteractionService, Task opTask, OperationResult result) { state = modelContext.getState(); @@ -55,9 +69,24 @@ public ModelOperationStatusDto(ModelContext modelContext) { } // primaryDelta - if (modelContext.getFocusContext().getPrimaryDelta() != null) { - primaryDelta = new DeltaDto(modelContext.getFocusContext().getPrimaryDelta()); - } + final List> primaryDeltas = new ArrayList<>(); +// final List> secondaryDeltas = new ArrayList<>(); + final List primaryScenes; +// final List secondaryScenes; + try { + addIgnoreNull(primaryDeltas, modelContext.getFocusContext().getPrimaryDelta()); +// addIgnoreNull(secondaryDeltas, modelContext.getFocusContext().getSecondaryDelta()); + for (ModelProjectionContext projCtx : modelContext.getProjectionContexts()) { + addIgnoreNull(primaryDeltas, projCtx.getPrimaryDelta()); +// addIgnoreNull(secondaryDeltas, projCtx.getExecutableDelta()); + } + primaryScenes = modelInteractionService.visualizeDeltas(primaryDeltas, opTask, result); +// secondaryScenes = modelInteractionService.visualizeDeltas(secondaryDeltas, opTask, result); + } catch (SchemaException e) { + throw new SystemException(e); // TODO + } + final WrapperScene primaryWrapperScene = new WrapperScene(primaryScenes, primaryDeltas.size() != 1 ? "PagePreviewChanges.primaryChangesMore" : "PagePreviewChanges.primaryChangesOne", primaryDeltas.size()); + primarySceneDto = new SceneDto(primaryWrapperScene); } } @@ -74,7 +103,7 @@ public String getFocusName() { return focusName; } - public DeltaDto getPrimaryDelta() { - return primaryDelta; + public SceneDto getPrimaryDelta() { + return primarySceneDto; } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/model/operationStatus/ModelOperationStatusPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/model/operationStatus/ModelOperationStatusPanel.java index c04e9f2c94a..9afce1255cc 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/model/operationStatus/ModelOperationStatusPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/model/operationStatus/ModelOperationStatusPanel.java @@ -19,6 +19,8 @@ import com.evolveum.midpoint.model.api.context.ModelState; import com.evolveum.midpoint.web.component.model.delta.DeltaDto; import com.evolveum.midpoint.web.component.model.delta.DeltaPanel; +import com.evolveum.midpoint.web.component.prism.show.SceneDto; +import com.evolveum.midpoint.web.component.prism.show.ScenePanel; import com.evolveum.midpoint.web.component.util.SimplePanel; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import org.apache.wicket.markup.html.basic.Label; @@ -48,7 +50,7 @@ protected void initLayout() { add(new Label(ID_FOCUS_NAME, new PropertyModel(getModel(), ModelOperationStatusDto.F_FOCUS_NAME))); - DeltaPanel deltaPanel = new DeltaPanel(ID_PRIMARY_DELTA, new PropertyModel(getModel(), ModelOperationStatusDto.F_PRIMARY_DELTA)); + ScenePanel deltaPanel = new ScenePanel(ID_PRIMARY_DELTA, new PropertyModel(getModel(), ModelOperationStatusDto.F_PRIMARY_DELTA)); deltaPanel.add(new VisibleEnableBehaviour() { @Override public boolean isVisible() { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/AbstractObjectMainPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/AbstractObjectMainPanel.html index d9887dadc72..5ceff33b623 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/AbstractObjectMainPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/AbstractObjectMainPanel.html @@ -29,6 +29,7 @@ + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/AbstractObjectMainPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/AbstractObjectMainPanel.java index e75bb47f7f8..762ee9b9305 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/AbstractObjectMainPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/objectdetails/AbstractObjectMainPanel.java @@ -17,6 +17,11 @@ import java.util.List; +import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.web.component.prism.show.PagePreviewChanges; +import com.evolveum.midpoint.web.page.admin.server.PageTaskEdit; +import com.evolveum.midpoint.web.util.OnePageParameterEncoder; import org.apache.commons.lang.Validate; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink; @@ -38,6 +43,7 @@ import com.evolveum.midpoint.web.page.admin.users.component.ExecuteChangeOptionsDto; import com.evolveum.midpoint.web.page.admin.users.component.ExecuteChangeOptionsPanel; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import org.apache.wicket.request.mapper.parameter.PageParameters; /** * @author semancik @@ -50,7 +56,8 @@ public abstract class AbstractObjectMainPanel extends Pane private static final String ID_EXECUTE_OPTIONS = "executeOptions"; private static final String ID_BACK = "back"; private static final String ID_SAVE = "save"; - + private static final String ID_PREVIEW_CHANGES = "previewChanges"; + private static final Trace LOGGER = TraceManager.getTrace(AbstractObjectMainPanel.class); private Form mainForm; @@ -137,6 +144,7 @@ protected void initLayoutOptions(PageAdminObjectDetails parentPage) { } protected void initLayoutButtons(PageAdminObjectDetails parentPage) { + initLayoutPreviewButton(parentPage); initLayoutSaveButton(parentPage); initLayoutBackButton(parentPage); } @@ -160,6 +168,25 @@ protected void onError(AjaxRequestTarget target, mainForm.add(saveButton); } + // TEMPORARY + protected void initLayoutPreviewButton(final PageAdminObjectDetails parentPage) { + AjaxSubmitButton previewButton = new AjaxSubmitButton(ID_PREVIEW_CHANGES, parentPage.createStringResource("pageAdminFocus.button.previewChanges")) { + + @Override + protected void onSubmit(AjaxRequestTarget target, + org.apache.wicket.markup.html.form.Form form) { + getDetailsPage().previewPerformed(target); + } + + @Override + protected void onError(AjaxRequestTarget target, + org.apache.wicket.markup.html.form.Form form) { + target.add(parentPage.getFeedbackPanel()); + } + }; + mainForm.add(previewButton); + } + protected void initLayoutBackButton(PageAdminObjectDetails parentPage) { AjaxButton back = new AjaxButton(ID_BACK, parentPage.createStringResource("pageAdminFocus.button.back")) { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java index f981ccdee49..e099647415c 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/ObjectWrapper.java @@ -332,6 +332,13 @@ public ObjectDelta getObjectDelta() throws SchemaException { if (itemWrapper instanceof PropertyWrapper) { ItemDelta pDelta = computePropertyDeltas((PropertyWrapper) itemWrapper, containerPath); if (!pDelta.isEmpty()) { + //HACK to remove a password replace delta is to be created + if (containerWrapper.getName().equals(CredentialsType.F_PASSWORD)) { + if (pDelta.getValuesToDelete() != null){ + pDelta.resetValuesToDelete(); + pDelta.setValuesToReplace(new ArrayList()); + } + } delta.addModification(pDelta); } } else if (itemWrapper instanceof ReferenceWrapper) { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismValuePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismValuePanel.java index 5628b9fa159..e52128d3283 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismValuePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/PrismValuePanel.java @@ -16,16 +16,6 @@ package com.evolveum.midpoint.web.component.prism; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; - -import javax.xml.datatype.XMLGregorianCalendar; -import javax.xml.namespace.QName; - import com.evolveum.midpoint.common.refinery.CompositeRefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; @@ -34,19 +24,42 @@ import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.query.*; +import com.evolveum.midpoint.prism.xml.XsdTypeMapper; +import com.evolveum.midpoint.schema.DeltaConvertor; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.RetrieveOption; +import com.evolveum.midpoint.schema.SelectorOptions; +import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.processor.ResourceAttribute; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ShadowUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.DOMUtil; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.component.form.ValueChoosePanel; +import com.evolveum.midpoint.web.component.input.*; +import com.evolveum.midpoint.web.component.model.delta.DeltaDto; +import com.evolveum.midpoint.web.component.model.delta.ModificationsPanel; +import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.model.LookupPropertyModel; +import com.evolveum.midpoint.web.page.admin.users.PageUser; import com.evolveum.midpoint.web.page.admin.users.component.AssociationValueChoicePanel; +import com.evolveum.midpoint.web.security.SecurityUtils; +import com.evolveum.midpoint.web.util.DateValidator; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; - +import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; +import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.Validate; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; -import org.apache.wicket.MarkupContainer; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.AjaxLink; @@ -64,37 +77,14 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.PropertyModel; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.prism.xml.XsdTypeMapper; -import com.evolveum.midpoint.schema.DeltaConvertor; -import com.evolveum.midpoint.schema.GetOperationOptions; -import com.evolveum.midpoint.schema.RetrieveOption; -import com.evolveum.midpoint.schema.SelectorOptions; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.processor.ObjectClassComplexTypeDefinition; -import com.evolveum.midpoint.schema.processor.ResourceAttribute; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.ShadowUtil; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.DOMUtil; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; -import com.evolveum.midpoint.web.component.form.ValueChoosePanel; -import com.evolveum.midpoint.web.component.input.AutoCompleteTextPanel; -import com.evolveum.midpoint.web.component.input.DatePanel; -import com.evolveum.midpoint.web.component.input.PasswordPanel; -import com.evolveum.midpoint.web.component.input.TextAreaPanel; -import com.evolveum.midpoint.web.component.input.TextPanel; -import com.evolveum.midpoint.web.component.input.TriStateComboPanel; -import com.evolveum.midpoint.web.component.input.UploadDownloadPanel; -import com.evolveum.midpoint.web.component.model.delta.DeltaDto; -import com.evolveum.midpoint.web.component.model.delta.ModificationsPanel; -import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; -import com.evolveum.midpoint.web.util.DateValidator; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.AssignmentCreationApprovalFormType; -import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; -import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.namespace.QName; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; /** * @author lazyman @@ -434,14 +424,6 @@ private Panel createTypedInputComponent(String id) { return new TextAreaPanel(id, new PropertyModel(model, baseExpression)); } - // the same for requester and approver comments in workflows [mederly] - this is really ugly, as it is specific to each approval form - if (AssignmentCreationApprovalFormType.F_REQUESTER_COMMENT.equals(definition.getName()) || - AssignmentCreationApprovalFormType.F_COMMENT.equals(definition.getName())) { - return new TextAreaPanel(id, new PropertyModel(model, baseExpression)); - } - - - if (ActivationType.F_ADMINISTRATIVE_STATUS.equals(definition.getName())) { return WebComponentUtil.createEnumPanel(ActivationStatusType.class, id, new PropertyModel(model, baseExpression), this); } else if(ActivationType.F_LOCKOUT_STATUS.equals(definition.getName())){ @@ -454,9 +436,15 @@ private Panel createTypedInputComponent(String id) { panel = new DatePanel(id, new PropertyModel(model, baseExpression)); } else if (ProtectedStringType.COMPLEX_TYPE.equals(valueType)) { + boolean showRemovePasswordButton = true; + if (pageBase instanceof PageUser && + ((PageUser) pageBase).getObjectWrapper().getObject() != null && + ((PageUser) pageBase).getObjectWrapper().getObject().getOid() != null && + ((PageUser) pageBase).getObjectWrapper().getObject().getOid().equals(SecurityUtils.getPrincipalUser().getOid())) { + showRemovePasswordButton = false; + } panel = new PasswordPanel(id, new PropertyModel(model, baseExpression), - model.getObject().isReadonly()); - + model.getObject().isReadonly(), showRemovePasswordButton); } else if (DOMUtil.XSD_BOOLEAN.equals(valueType)) { panel = new TriStateComboPanel(id, new PropertyModel(model, baseExpression)); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/PagePreviewChanges.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/PagePreviewChanges.html new file mode 100644 index 00000000000..3ea6163359a --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/PagePreviewChanges.html @@ -0,0 +1,31 @@ + + + + + + +
+
+
+

+

+ + + + \ No newline at end of file diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/PagePreviewChanges.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/PagePreviewChanges.java new file mode 100644 index 00000000000..059791e9f89 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/PagePreviewChanges.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.model.api.ModelInteractionService; +import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.api.context.ModelProjectionContext; +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.application.AuthorizationAction; +import com.evolveum.midpoint.web.application.PageDescriptor; +import com.evolveum.midpoint.web.component.AjaxButton; +import com.evolveum.midpoint.web.page.admin.home.PageDashboard; +import com.evolveum.midpoint.web.page.admin.workflow.PageAdminWorkItems; +import com.evolveum.midpoint.web.util.OnePageParameterEncoder; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; + +import java.util.ArrayList; +import java.util.List; + +import static org.apache.commons.collections.CollectionUtils.addIgnoreNull; + +/** + * @author mederly + */ +@PageDescriptor(url = "/admin/workItem", encoder = OnePageParameterEncoder.class, action = { + @AuthorizationAction(actionUri = PageAdminWorkItems.AUTH_WORK_ITEMS_ALL, + label = PageAdminWorkItems.AUTH_WORK_ITEMS_ALL_LABEL, + description = PageAdminWorkItems.AUTH_WORK_ITEMS_ALL_DESCRIPTION), + @AuthorizationAction(actionUri = AuthorizationConstants.AUTZ_UI_WORK_ITEM_URL, + label = "PageWorkItem.auth.workItem.label", + description = "PageWorkItem.auth.workItem.description")}) +public class PagePreviewChanges extends PageAdminWorkItems { // TODO extends + + private static final String ID_PRIMARY_DELTAS_SCENE = "primaryDeltas"; + private static final String ID_SECONDARY_DELTAS_SCENE = "secondaryDeltas"; + private static final String ID_BACK = "back"; + + private static final Trace LOGGER = TraceManager.getTrace(PagePreviewChanges.class); + + private IModel primaryDeltasModel; + private IModel secondaryDeltasModel; + + public PagePreviewChanges(ModelContext modelContext, ModelInteractionService modelInteractionService, PageBase previousPage) { // TODO remove previousPage + setPreviousPage(previousPage); + final List> primaryDeltas = new ArrayList<>(); + final List> secondaryDeltas = new ArrayList<>(); + final List primaryScenes; + final List secondaryScenes; + try { + if (modelContext != null) { + if (modelContext.getFocusContext() != null) { + addIgnoreNull(primaryDeltas, modelContext.getFocusContext().getPrimaryDelta()); + addIgnoreNull(secondaryDeltas, modelContext.getFocusContext().getSecondaryDelta()); + } + for (ModelProjectionContext projCtx : modelContext.getProjectionContexts()) { + addIgnoreNull(primaryDeltas, projCtx.getPrimaryDelta()); + addIgnoreNull(secondaryDeltas, projCtx.getExecutableDelta()); + } + } + LOGGER.info("Primary deltas:\n{}", DebugUtil.debugDump(primaryDeltas)); + LOGGER.info("Secondary deltas:\n{}", DebugUtil.debugDump(secondaryDeltas)); + + Task task = createSimpleTask("visualize"); + primaryScenes = modelInteractionService.visualizeDeltas(primaryDeltas, task, task.getResult()); + secondaryScenes = modelInteractionService.visualizeDeltas(secondaryDeltas, task, task.getResult()); + } catch (SchemaException e) { + throw new SystemException(e); // TODO + } + LOGGER.info("Creating context DTO for primary deltas:\n{}", DebugUtil.debugDump(primaryScenes)); + LOGGER.info("Creating context DTO for secondary deltas:\n{}", DebugUtil.debugDump(secondaryScenes)); + + final WrapperScene primaryScene = new WrapperScene(primaryScenes, + primaryDeltas.size() != 1 ? "PagePreviewChanges.primaryChangesMore" : "PagePreviewChanges.primaryChangesOne", primaryDeltas.size()); + final WrapperScene secondaryScene = new WrapperScene(secondaryScenes, + secondaryDeltas.size() != 1 ? "PagePreviewChanges.secondaryChangesMore" : "PagePreviewChanges.secondaryChangesOne", secondaryDeltas.size()); + final SceneDto primarySceneDto = new SceneDto(primaryScene); + final SceneDto secondarySceneDto = new SceneDto(secondaryScene); + primaryDeltasModel = new AbstractReadOnlyModel() { + @Override + public SceneDto getObject() { + return primarySceneDto; + } + }; + secondaryDeltasModel = new AbstractReadOnlyModel() { + @Override + public SceneDto getObject() { + return secondarySceneDto; + } + }; + initLayout(); + } + + private void initLayout() { + Form mainForm = new Form("mainForm"); + mainForm.setMultiPart(true); + add(mainForm); + + mainForm.add(new ScenePanel(ID_PRIMARY_DELTAS_SCENE, primaryDeltasModel)); + mainForm.add(new ScenePanel(ID_SECONDARY_DELTAS_SCENE, secondaryDeltasModel)); + initButtons(mainForm); + } + + private void initButtons(Form mainForm) { + AjaxButton cancel = new AjaxButton(ID_BACK, createStringResource("pageAccount.button.back")) { // TODO key + @Override + public void onClick(AjaxRequestTarget target) { + cancelPerformed(target); + } + }; + mainForm.add(cancel); + } + + private void cancelPerformed(AjaxRequestTarget target) { + goBack(PageDashboard.class); + } + +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneButtonPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneButtonPanel.html new file mode 100644 index 00000000000..3a3ae8104d8 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneButtonPanel.html @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneButtonPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneButtonPanel.java new file mode 100644 index 00000000000..df80f16f94a --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneButtonPanel.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.web.component.prism.PrismObjectPanel; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.AjaxLink; +import org.apache.wicket.behavior.AttributeAppender; +import org.apache.wicket.markup.html.image.Image; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.resource.PackageResourceReference; + +/** + * @author mserbak + * @author lazyman + */ +public class SceneButtonPanel extends Panel { + + public SceneButtonPanel(String id, IModel model) { + super(id); + + initLayout(model); + } + + private void initLayout(final IModel model) { + AjaxLink minimize = new AjaxLink("minimizeButton") { + + @Override + public void onClick(AjaxRequestTarget target) { + minimizeOnClick(target); + } + }; + add(minimize); + + Image minimizeImg = new Image("minimizeImg", new AbstractReadOnlyModel() { + + @Override + public Object getObject() { + SceneDto dto = model.getObject(); + if (dto.isMinimized()) { + return new PackageResourceReference(PrismObjectPanel.class, "Maximize.png"); + } + return new PackageResourceReference(PrismObjectPanel.class, "Minimize.png"); + } + }); + minimizeImg.add(new AttributeAppender("title", new AbstractReadOnlyModel() { + + @Override + public Object getObject() { + SceneDto dto = model.getObject(); + if (dto.isMinimized()) { + return getString("prismOptionButtonPanel.maximize"); + } + return getString("prismOptionButtonPanel.minimize"); + } + }, "")); + minimize.add(minimizeImg); + } + + public void minimizeOnClick(AjaxRequestTarget target) { + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneDto.java new file mode 100644 index 00000000000..b37c59bc5cd --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneDto.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.model.api.visualizer.Name; +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.model.api.visualizer.SceneDeltaItem; +import com.evolveum.midpoint.model.api.visualizer.SceneItem; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.delta.ChangeType; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * @author mederly + */ +public class SceneDto implements Serializable { + + public static final java.lang.String F_NAME = "name"; + public static final java.lang.String F_CHANGE_TYPE = "changeType"; + public static final java.lang.String F_OBJECT_TYPE = "objectType"; + public static final java.lang.String F_DESCRIPTION = "description"; + public static final java.lang.String F_ITEMS = "items"; + public static final java.lang.String F_PARTIAL_SCENES = "partialScenes"; + + private Scene scene; + private boolean minimized; + + private final List items = new ArrayList<>(); + private final List partialScenes = new ArrayList<>(); + + public SceneDto(Scene scene) { + this.scene = scene; + for (SceneItem item : scene.getItems()) { + if (item != null) { + items.add(new SceneItemDto(this, item)); + } + } + for (Scene sub : scene.getPartialScenes()) { + if (sub != null) { + partialScenes.add(new SceneDto(sub)); + } + } + } + + public Scene getScene() { + return scene; + } + + public void setScene(Scene scene) { + this.scene = scene; + } + + public boolean isMinimized() { + return minimized; + } + + public void setMinimized(boolean minimized) { + this.minimized = minimized; + } + + public List getPartialScenes() { + return partialScenes; + } + + public List getItems() { + return items; + } + + public String getName() { + if (scene.getName() != null) { + if (scene.getName().getDisplayName() != null) { + return scene.getName().getDisplayName(); + } else { + return scene.getName().getSimpleName(); + } + } else { + return "(unnamed)"; // TODO i18n + } + } + + public String getDescription() { + Name name = scene.getName(); + if (name == null) { + return ""; + } + if (scene.getSourceDefinition() != null && !(scene.getSourceDefinition() instanceof PrismObjectDefinition)) { + return ""; + } + if (name.getSimpleName() != null && !name.getSimpleName().equals(getName())) { + return "(" + name.getSimpleName() + ")"; + } + return ""; + } + + public ChangeType getChangeType() { + return scene.getChangeType(); + } + + public boolean containsDeltaItems() { + for (SceneItem item : scene.getItems()) { + if (item instanceof SceneDeltaItem) { + return true; + } + } + return false; + } + + public boolean isWrapper() { + return scene instanceof WrapperScene; + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemDto.java new file mode 100644 index 00000000000..5ae7c8a74b7 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemDto.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.model.api.visualizer.*; +import org.apache.commons.lang3.Validate; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * @author mederly + */ +public class SceneItemDto implements Serializable { + + public static final String F_NAME = "name"; + public static final String F_LINES = "lines"; + + @NotNull private final SceneItem sceneItem; + @NotNull private final SceneDto sceneDto; + @NotNull private final List lines; + + public SceneItemDto(@NotNull SceneDto sceneDto, @NotNull SceneItem sceneItem) { + Validate.notNull(sceneDto); + Validate.notNull(sceneItem); + this.sceneDto = sceneDto; + this.sceneItem = sceneItem; + this.lines = computeLines(); + } + + public String getName() { + Name n = sceneItem.getName(); + if (n == null) { + return ""; + } else if (n.getDisplayName() != null) { + return n.getDisplayName(); + } else { + return n.getSimpleName(); + } + } + + public String getNewValue() { + return String.valueOf(sceneItem.getNewValues()); + } + + public List computeLines() { + List rv = new ArrayList<>(); + int index = 0; + if (!isDelta()) { + for (SceneItemValue itemValue : sceneItem.getNewValues()) { + rv.add(new SceneItemLineDto(this, null, itemValue, index++, false)); + } + } else { + SceneDeltaItem deltaItem = (SceneDeltaItem) sceneItem; + for (SceneItemValue itemValue : deltaItem.getUnchangedValues()) { + rv.add(new SceneItemLineDto(this, null, itemValue, index++, false)); + } + Iterator deletedValuesIter = deltaItem.getDeletedValues().iterator(); + Iterator addedValuesIter = deltaItem.getAddedValues().iterator(); + while (deletedValuesIter.hasNext() || addedValuesIter.hasNext()) { + SceneItemValue deletedValue = deletedValuesIter.hasNext() ? deletedValuesIter.next() : null; + SceneItemValue addedValue = addedValuesIter.hasNext() ? addedValuesIter.next() : null; + rv.add(new SceneItemLineDto(this, deletedValue, addedValue, index++, true)); + } + } + return rv; + } + + @NotNull + public List getLines() { + return lines; + } + + public boolean isDelta() { + return sceneItem instanceof SceneDeltaItem; + } + + public boolean isDeltaScene() { + return sceneDto.containsDeltaItems(); + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLineDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLineDto.java new file mode 100644 index 00000000000..316a1f7e39f --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLineDto.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.model.api.visualizer.SceneItemValue; + +import java.io.Serializable; + +/** + * @author mederly + */ +public class SceneItemLineDto implements Serializable { + + public static final String F_NAME = "name"; + public static final String F_OLD_VALUE = "oldValue"; + public static final String F_NEW_VALUE = "newValue"; + public static final String F_NUMBER_OF_LINES = "numberOfLines"; + + private final SceneItemDto sceneItemDto; + private final SceneItemValue sceneItemOldValue; + private final SceneItemValue sceneItemNewValue; + private final int index; + private final boolean isDelta; + + public SceneItemLineDto(SceneItemDto sceneItemDto, SceneItemValue sceneItemOldValue, SceneItemValue sceneItemNewValue, int index, boolean isDelta) { + this.sceneItemDto = sceneItemDto; + this.sceneItemOldValue = sceneItemOldValue; + this.sceneItemNewValue = sceneItemNewValue; + this.index = index; + this.isDelta = isDelta; + } + + public String getName() { + return sceneItemDto.getName(); + } + + public String getOldValue() { + return sceneItemOldValue != null ? sceneItemOldValue.getText() : null; + } + + public String getNewValue() { + return sceneItemNewValue != null ? sceneItemNewValue.getText() : null; + } + + public Integer getNumberOfLines() { + return sceneItemDto.getLines().size(); + } + + public boolean isFirst() { + return index == 0; + } + + public boolean isDelta() { + return isDelta; + } + + public boolean isDeltaScene() { + return sceneItemDto.isDeltaScene(); + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLinePanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLinePanel.html new file mode 100644 index 00000000000..ecb997a1087 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLinePanel.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLinePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLinePanel.java new file mode 100644 index 00000000000..f8da41f8f3c --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemLinePanel.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; +import org.apache.wicket.AttributeModifier; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; + +/** + * @author mederly + */ +public class SceneItemLinePanel extends BasePanel { + + private static final String ID_NAME_CONTAINER = "nameContainer"; + private static final String ID_NAME = "name"; + private static final String ID_OLD_VALUE_CONTAINER = "oldValueContainer"; + private static final String ID_OLD_VALUE = "oldValue"; + private static final String ID_NEW_VALUE_CONTAINER = "newValueContainer"; + private static final String ID_NEW_VALUE = "newValue"; + + private static final Trace LOGGER = TraceManager.getTrace(SceneItemLinePanel.class); + + public SceneItemLinePanel(String id, IModel model) { + super(id, model); + setOutputMarkupId(true); + + initLayout(); + } + + private void initLayout() { + WebMarkupContainer nameCell = new WebMarkupContainer(ID_NAME_CONTAINER); + nameCell.add(new AttributeModifier("rowspan", new PropertyModel(getModel(), SceneItemLineDto.F_NUMBER_OF_LINES))); + Label label = new Label("name", new PropertyModel(getModel(), SceneItemLineDto.F_NAME)); + nameCell.add(label); + nameCell.add(new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return getModelObject().isFirst(); + } + }); + add(nameCell); + + WebMarkupContainer oldValueCell = new WebMarkupContainer(ID_OLD_VALUE_CONTAINER); + oldValueCell.add(new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return getModelObject().isDelta(); + } + }); + oldValueCell.add(new Label(ID_OLD_VALUE, new PropertyModel(getModel(), SceneItemLineDto.F_OLD_VALUE))); + add(oldValueCell); + + WebMarkupContainer newValueCell = new WebMarkupContainer(ID_NEW_VALUE_CONTAINER); + newValueCell.add(new Label(ID_NEW_VALUE, new PropertyModel(getModel(), SceneItemLineDto.F_NEW_VALUE))); + newValueCell.add(new AttributeModifier("colspan", new AbstractReadOnlyModel() { + @Override + public Integer getObject() { + return !getModelObject().isDelta() && getModelObject().isDeltaScene() ? 2 : 1; + } + })); + newValueCell.add(new AttributeModifier("align", new AbstractReadOnlyModel() { + @Override + public String getObject() { + return !getModelObject().isDelta() && getModelObject().isDeltaScene() ? "center" : null; + } + })); + add(newValueCell); + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemPanel.html new file mode 100644 index 00000000000..47bd3070ee1 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemPanel.html @@ -0,0 +1,24 @@ + + + + + +
+
+
+ + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemPanel.java new file mode 100644 index 00000000000..7e05fd951e6 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneItemPanel.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; + +import java.util.List; + +/** + * @author lazyman + */ +public class SceneItemPanel extends Panel { + + private static final String ID_ITEM_LINES = "itemLines"; + private static final String ID_ITEM_LINE = "itemLine"; + + private static final Trace LOGGER = TraceManager.getTrace(SceneItemPanel.class); + + private boolean showHeader = true; + + public SceneItemPanel(String id, IModel model) { + super(id); + setOutputMarkupId(true); + + initLayout(model); + } + + private void initLayout(final IModel model) { + ListView items = new ListView(ID_ITEM_LINES, new PropertyModel>(model, SceneItemDto.F_LINES)) { + @Override + protected void populateItem(ListItem item) { + SceneItemLinePanel panel = new SceneItemLinePanel(ID_ITEM_LINE, item.getModel()); + panel.setOutputMarkupPlaceholderTag(true); + item.add(panel); + } + }; + items.setReuseItems(true); + add(items); + } + +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/ScenePanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/ScenePanel.html new file mode 100644 index 00000000000..231005cd843 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/ScenePanel.html @@ -0,0 +1,53 @@ + + + + + +
+
+
+
+
+ + + + +
+
+
+
+ +
+ + + + + + + +
+
+
+
+
+
+
+
+
+
+ + diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/ScenePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/ScenePanel.java new file mode 100644 index 00000000000..e6c11a3d366 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/ScenePanel.java @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.delta.ChangeType; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.StringResourceModel; + +import java.util.List; + +/** + * @author mederly + */ +public class ScenePanel extends BasePanel { + + private static final String STRIPED_CLASS = "striped"; + private static final String ID_ITEMS_TABLE = "itemsTable"; + private static final String ID_ITEMS = "items"; + private static final String ID_ITEM = "item"; + private static final String ID_PARTIAL_SCENES = "partialScenes"; + private static final String ID_PARTIAL_SCENE = "partialScene"; + + private static final Trace LOGGER = TraceManager.getTrace(ScenePanel.class); + public static final String ID_OPTION_BUTTONS = "optionButtons"; + public static final String ID_HEADER_PANEL = "headerPanel"; + public static final String ID_HEADER_DESCRIPTION = "description"; + public static final String ID_HEADER_WRAPPER_DISPLAY_NAME = "wrapperDisplayName"; + public static final String ID_HEADER_NAME = "name"; + public static final String ID_HEADER_CHANGE_TYPE = "changeType"; + public static final String ID_HEADER_OBJECT_TYPE = "objectType"; + public static final String ID_BODY = "body"; + public static final String ID_OLD_VALUE_LABEL = "oldValueLabel"; + public static final String ID_NEW_VALUE_LABEL = "newValueLabel"; + public static final String ID_VALUE_LABEL = "valueLabel"; + + public ScenePanel(String id, IModel model) { + super(id, model); + setOutputMarkupId(true); + + LOGGER.trace("Creating object panel for {}", model.getObject()); + + initLayout(); + } + + private AjaxEventBehavior createHeaderOnClickBehaviour(final IModel model) { + return new AjaxEventBehavior("click") { + @Override + protected void onEvent(AjaxRequestTarget target) { + headerOnClickPerformed(target, model); + } + }; + } + + private void initLayout() { + final IModel model = getModel(); + + WebMarkupContainer headerPanel = new WebMarkupContainer(ID_HEADER_PANEL); + add(headerPanel); + + headerPanel.add(new SceneButtonPanel(ID_OPTION_BUTTONS, model) { + @Override + public void minimizeOnClick(AjaxRequestTarget target) { + headerOnClickPerformed(target, model); + } + }); + + Label headerChangeType = new Label(ID_HEADER_CHANGE_TYPE, new ChangeTypeModel()); + Label headerObjectType = new Label(ID_HEADER_OBJECT_TYPE, new ObjectTypeModel()); + Label headerName = new Label(ID_HEADER_NAME, new PropertyModel(model, SceneDto.F_NAME)); + Label headerDescription = new Label(ID_HEADER_DESCRIPTION, new PropertyModel(model, SceneDto.F_DESCRIPTION)); + Label headerWrapperDisplayName = new Label(ID_HEADER_WRAPPER_DISPLAY_NAME, + new AbstractReadOnlyModel() { + @Override + public String getObject() { + String key = ((WrapperScene) getModelObject().getScene()).getDisplayNameKey(); + Object[] parameters = ((WrapperScene) getModelObject().getScene()).getDisplayNameParameters(); + return new StringResourceModel(key, this).setModel(null) + .setDefaultValue(key) + .setParameters(parameters).getObject(); + } + }); + + headerPanel.add(headerChangeType); + headerPanel.add(headerObjectType); + headerPanel.add(headerName); + headerPanel.add(headerDescription); + headerPanel.add(headerWrapperDisplayName); + + headerChangeType.add(createHeaderOnClickBehaviour(model)); + headerObjectType.add(createHeaderOnClickBehaviour(model)); + headerName.add(createHeaderOnClickBehaviour(model)); + headerDescription.add(createHeaderOnClickBehaviour(model)); + headerWrapperDisplayName.add(createHeaderOnClickBehaviour(model)); + + VisibleEnableBehaviour visibleIfNotWrapper = new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return !getModelObject().isWrapper(); + } + }; + VisibleEnableBehaviour visibleIfWrapper = new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return getModelObject().isWrapper(); + } + }; + headerChangeType.add(visibleIfNotWrapper); + headerObjectType.add(visibleIfNotWrapper); + headerName.add(visibleIfNotWrapper); + headerDescription.add(visibleIfNotWrapper); + headerWrapperDisplayName.add(visibleIfWrapper); + + WebMarkupContainer body = new WebMarkupContainer(ID_BODY); + body.add(new VisibleEnableBehaviour() { + + @Override + public boolean isVisible() { + SceneDto wrapper = model.getObject(); + return !wrapper.isMinimized(); + } + }); + add(body); + + WebMarkupContainer itemsTable = new WebMarkupContainer(ID_ITEMS_TABLE); + itemsTable.add(new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return !model.getObject().getItems().isEmpty(); + } + }); + WebMarkupContainer oldValueLabel = new WebMarkupContainer(ID_OLD_VALUE_LABEL); + oldValueLabel.add(new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return model.getObject().containsDeltaItems(); + } + }); + itemsTable.add(oldValueLabel); + WebMarkupContainer newValueLabel = new WebMarkupContainer(ID_NEW_VALUE_LABEL); + newValueLabel.add(new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return model.getObject().containsDeltaItems(); + } + }); + itemsTable.add(newValueLabel); + WebMarkupContainer valueLabel = new WebMarkupContainer(ID_VALUE_LABEL); + valueLabel.add(new VisibleEnableBehaviour() { + @Override + public boolean isVisible() { + return !model.getObject().containsDeltaItems(); + } + }); + itemsTable.add(valueLabel); + ListView items = new ListView(ID_ITEMS, new PropertyModel>(model, SceneDto.F_ITEMS)) { + @Override + protected void populateItem(ListItem item) { + SceneItemPanel panel = new SceneItemPanel(ID_ITEM, item.getModel()); + panel.setOutputMarkupPlaceholderTag(true); + item.add(panel); + } + }; + items.setReuseItems(true); + itemsTable.add(items); + body.add(itemsTable); + + ListView partialScenes = new ListView(ID_PARTIAL_SCENES, new PropertyModel>(model, SceneDto.F_PARTIAL_SCENES)) { + @Override + protected void populateItem(ListItem item) { + ScenePanel panel = new ScenePanel(ID_PARTIAL_SCENE, item.getModel()); + panel.setOutputMarkupPlaceholderTag(true); + item.add(panel); + } + }; + partialScenes.setReuseItems(true); + body.add(partialScenes); + } + + public void headerOnClickPerformed(AjaxRequestTarget target, IModel model) { + SceneDto dto = model.getObject(); + dto.setMinimized(!dto.isMinimized()); + target.add(this); + } + + private class ChangeTypeModel extends AbstractReadOnlyModel { + @Override + public String getObject() { + ChangeType changeType = getModel().getObject().getScene().getChangeType(); + if (changeType == null) { + return ""; + } + return WebComponentUtil.createLocalizedModelForEnum(changeType, ScenePanel.this).getObject(); + } + } + + private class ObjectTypeModel extends AbstractReadOnlyModel { + @Override + public String getObject() { + Scene scene = getModel().getObject().getScene(); + PrismContainerDefinition def = scene.getSourceDefinition(); + if (def == null) { + return ""; + } + if (def instanceof PrismObjectDefinition) { + return PageBase.createStringResourceStatic(ScenePanel.this, "ObjectType." +def.getTypeName().getLocalPart()).getObject(); + } else { + return ""; + } + } + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneUtil.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneUtil.java new file mode 100644 index 00000000000..d9cde41de04 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/SceneUtil.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.model.api.ModelInteractionService; +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.schema.DeltaConvertor; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTreeDeltasType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ProjectionObjectDeltaType; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author mederly + */ +public class SceneUtil { + + public static Scene visualizeObjectTreeDeltas(ObjectTreeDeltasType deltas, String displayNameKey, + PrismContext prismContext, ModelInteractionService modelInteractionService, + Task task, OperationResult result) throws SchemaException { + List scenes = new ArrayList<>(); + if (deltas.getFocusPrimaryDelta() != null) { + ObjectDelta delta = DeltaConvertor.createObjectDelta(deltas.getFocusPrimaryDelta(), prismContext); + scenes.add(modelInteractionService.visualizeDelta(delta, task, result)); + } + for (ProjectionObjectDeltaType projectionObjectDelta : deltas.getProjectionPrimaryDelta()) { + ObjectDelta delta = DeltaConvertor.createObjectDelta(projectionObjectDelta.getPrimaryDelta(), prismContext); + scenes.add(modelInteractionService.visualizeDelta(delta, task, result)); + } + return new WrapperScene(scenes, displayNameKey); + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/WrapperScene.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/WrapperScene.java new file mode 100644 index 00000000000..f6d242f47b5 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/prism/show/WrapperScene.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.prism.show; + +import com.evolveum.midpoint.model.api.visualizer.Name; +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.model.api.visualizer.SceneItem; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.delta.ChangeType; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.util.DebugUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Artificial implementation of a scene used to hold a list of deltas. + * (A bit of hack, unfortunately.) + * + * @author mederly + */ +public class WrapperScene implements Scene { + + private String displayNameKey; + private Object[] displayNameParameters; + private List partialScenes; + + public WrapperScene(List partialScenes, String displayNameKey, Object... displayNameParameters) { + this.partialScenes = partialScenes; + this.displayNameKey = displayNameKey; + this.displayNameParameters = displayNameParameters; + } + + public String getDisplayNameKey() { + return displayNameKey; + } + + public Object[] getDisplayNameParameters() { + return displayNameParameters; + } + + @Override + public Name getName() { + return new Name() { + + @Override + public String getSimpleName() { + return ""; + } + + @Override + public String getDisplayName() { + return null; + } + + @Override + public String getId() { + return null; + } + + @Override + public String getDescription() { + return null; + } + }; + } + + @Override + public ChangeType getChangeType() { + return null; + } + + @NotNull + @Override + public List getPartialScenes() { + return partialScenes; + } + + @NotNull + @Override + public List getItems() { + return Collections.emptyList(); + } + + @Override + public boolean isOperational() { + return false; + } + + @Override + public Scene getOwner() { + return null; + } + + @Override + public ItemPath getSourceRelPath() { + return null; + } + + @Override + public ItemPath getSourceAbsPath() { + return null; + } + + @Override + public PrismContainerValue getSourceValue() { + return null; + } + + @Override + public PrismContainerDefinition getSourceDefinition() { + return null; + } + + @Override + public ObjectDelta getSourceDelta() { + return null; + } + + @Override + public String debugDump() { + return debugDump(0); + } + + @Override + public String debugDump(int indent) { + return DebugUtil.debugDump(partialScenes, indent); + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReporter.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReporter.java index c0c37f8b204..980fee049bf 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReporter.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReporter.java @@ -16,10 +16,8 @@ package com.evolveum.midpoint.web.component.progress; -import com.evolveum.midpoint.model.api.ModelExecuteOptions; -import com.evolveum.midpoint.model.api.ModelService; -import com.evolveum.midpoint.model.api.PolicyViolationException; -import com.evolveum.midpoint.model.api.ProgressListener; +import com.evolveum.midpoint.model.api.*; +import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.SecurityEnforcer; @@ -42,7 +40,6 @@ import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.AjaxSelfUpdatingTimerBehavior; import org.apache.wicket.behavior.Behavior; -import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.model.Model; import org.apache.wicket.util.time.Duration; import org.springframework.security.core.Authentication; @@ -83,8 +80,9 @@ public class ProgressReporter implements Serializable { private int refreshInterval; private boolean asynchronousExecution; private boolean abortEnabled; - - public ProgressPanel getProgressPanel() { + private ModelContext previewResult; // Temporary - TODO rethink this... + + public ProgressPanel getProgressPanel() { return progressPanel; } @@ -132,19 +130,26 @@ public void onSaveSubmit() { * @param result Operation result. * @param target AjaxRequestTarget into which any synchronous changes are signalized. */ - public void executeChanges(final Collection> deltas, final ModelExecuteOptions options, final Task task, final OperationResult result, AjaxRequestTarget target) { + public void executeChanges(final Collection> deltas, + final boolean previewOnly, final ModelExecuteOptions options, final Task task, final OperationResult result, AjaxRequestTarget target) { parentPage.startProcessing(target, result); ModelService modelService = parentPage.getModelService(); + ModelInteractionService modelInteractionService = parentPage.getModelInteractionService(); if (asynchronousExecution) { - executeChangesAsync(deltas, options, task, result, target, modelService); + executeChangesAsync(deltas, previewOnly, options, task, result, target, modelService, modelInteractionService); } else { - executeChangesSync(deltas, options, task, result, target, modelService); + executeChangesSync(deltas, previewOnly, options, task, result, target, modelService, modelInteractionService); } } - private void executeChangesSync(Collection> deltas, ModelExecuteOptions options, Task task, OperationResult result, AjaxRequestTarget target, ModelService modelService) { + private void executeChangesSync(Collection> deltas, boolean previewOnly, ModelExecuteOptions options, Task task, + OperationResult result, AjaxRequestTarget target, ModelService modelService, ModelInteractionService modelInteractionService) { try { - modelService.executeChanges(deltas, options, task, result); + if (previewOnly) { + previewResult = modelInteractionService.previewChanges(deltas, options, task, result); + } else { + modelService.executeChanges(deltas, options, task, result); + } result.computeStatusIfUnknown(); } catch (CommunicationException |ObjectAlreadyExistsException |ExpressionEvaluationException | PolicyViolationException |SchemaException |SecurityViolationException | @@ -157,7 +162,9 @@ private void executeChangesSync(Collection> de parentPage.finishProcessing(target, result); } - private void executeChangesAsync(final Collection> deltas, final ModelExecuteOptions options, final Task task, final OperationResult result, AjaxRequestTarget target, final ModelService modelService) { + private void executeChangesAsync(final Collection> deltas, final boolean previewOnly, + final ModelExecuteOptions options, final Task task, final OperationResult result, AjaxRequestTarget target, + final ModelService modelService, final ModelInteractionService modelInteractionService) { final SecurityEnforcer enforcer = parentPage.getSecurityEnforcer(); final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); @@ -175,7 +182,11 @@ public void run() { try { enforcer.setupPreAuthenticatedSecurityContext(authentication); progressPanel.recordExecutionStart(); - modelService.executeChanges(deltas, options, task, Collections.singleton((ProgressListener) progressListener), result); + if (previewOnly) { + previewResult = modelInteractionService.previewChanges(deltas, options, task, Collections.singleton((ProgressListener) progressListener), result); + } else { + modelService.executeChanges(deltas, options, task, Collections.singleton((ProgressListener) progressListener), result); + } } catch (CommunicationException|ObjectAlreadyExistsException|ExpressionEvaluationException| PolicyViolationException|SchemaException|SecurityViolationException| ConfigurationException|ObjectNotFoundException|RuntimeException e) { @@ -313,4 +324,7 @@ public void clearProgressPanel() { progressPanel.getModelObject().clear(); } + public ModelContext getPreviewResult() { + return previewResult; + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReportingAwarePage.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReportingAwarePage.java index e3018c2005b..71e77daf0ff 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReportingAwarePage.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/progress/ProgressReportingAwarePage.java @@ -16,6 +16,7 @@ package com.evolveum.midpoint.web.component.progress; +import com.evolveum.midpoint.model.api.ModelInteractionService; import com.evolveum.midpoint.model.api.ModelService; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.SecurityEnforcer; @@ -46,6 +47,8 @@ public interface ProgressReportingAwarePage { ModelService getModelService(); + ModelInteractionService getModelInteractionService(); + SecurityEnforcer getSecurityEnforcer(); Task createSimpleTask(String name); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchFormPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchFormPanel.html new file mode 100644 index 00000000000..eeaf412e252 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchFormPanel.html @@ -0,0 +1,21 @@ + + + +
+
+ + \ No newline at end of file diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchFormPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchFormPanel.java new file mode 100644 index 00000000000..2c020998e83 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchFormPanel.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.search; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.model.IModel; + +/** + * @author Viliam Repan (lazyman) + */ +public class SearchFormPanel extends BasePanel { + + private static final String ID_SEARCH = "search"; + private static final String ID_SEARCH_FORM = "searchForm"; + + public SearchFormPanel(String id, IModel model) { + super(id, model); + + initLayout(); + } + + private void initLayout() { + final Form searchForm = new Form(ID_SEARCH_FORM); + add(searchForm); + searchForm.setOutputMarkupId(true); + + SearchPanel search = new SearchPanel(ID_SEARCH, getModel()) { + + @Override + public void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { + SearchFormPanel.this.searchPerformed(query, target); + } + }; + searchForm.add(search); + } + + protected void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { + + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchItemPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchItemPanel.java index 86b0711aaf2..c8d06ca1958 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchItemPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/search/SearchItemPanel.java @@ -25,7 +25,6 @@ import com.evolveum.midpoint.web.component.AjaxButton; import com.evolveum.midpoint.web.component.AjaxSubmitButton; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; - import org.apache.commons.lang.StringUtils; import org.apache.wicket.AttributeModifier; import org.apache.wicket.MarkupContainer; @@ -447,10 +446,13 @@ public Object getDisplayValue(DisplayableValue object) { public String getIdValue(DisplayableValue object, int index) { return Integer.toString(index); } - + @Override public DisplayableValue getObject(String id, IModel>> choices) { - return choices.getObject().get(Integer.parseInt(id)); + if (StringUtils.isEmpty(id)) { + return null; + } + return choices.getObject().get(Integer.parseInt(id)); } @Override diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WfDeltasPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WfDeltasPanel.java index 551dbf870f4..b415a5b931f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WfDeltasPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WfDeltasPanel.java @@ -18,6 +18,8 @@ import com.evolveum.midpoint.web.component.model.delta.DeltaDto; import com.evolveum.midpoint.web.component.model.delta.DeltaPanel; +import com.evolveum.midpoint.web.component.prism.show.SceneDto; +import com.evolveum.midpoint.web.component.prism.show.ScenePanel; import com.evolveum.midpoint.web.component.util.SimplePanel; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.page.admin.server.dto.TaskDto; @@ -48,17 +50,17 @@ public WfDeltasPanel(String id, IModel model) { @Override protected void initLayout() { - add(new ListView(ID_DELTA_IN_LIST, new PropertyModel>(getModel(), TaskDto.F_WORKFLOW_DELTAS_IN)) { + add(new ListView(ID_DELTA_IN_LIST, new PropertyModel>(getModel(), TaskDto.F_WORKFLOW_DELTAS_IN)) { @Override - protected void populateItem(ListItem item) { - item.add(new DeltaPanel(ID_DELTA_IN, item.getModel())); + protected void populateItem(ListItem item) { + item.add(new ScenePanel(ID_DELTA_IN, item.getModel())); } }); - ListView deltaOutListView = new ListView(ID_DELTA_OUT_LIST, new PropertyModel>(getModel(), TaskDto.F_WORKFLOW_DELTAS_OUT)) { + ListView deltaOutListView = new ListView(ID_DELTA_OUT_LIST, new PropertyModel>(getModel(), TaskDto.F_WORKFLOW_DELTAS_OUT)) { @Override - protected void populateItem(ListItem item) { - item.add(new DeltaPanel(ID_DELTA_OUT, item.getModel())); + protected void populateItem(ListItem item) { + item.add(new ScenePanel(ID_DELTA_OUT, item.getModel())); } }; deltaOutListView.add(new VisibleEnableBehaviour() { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WfHistoryPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WfHistoryPanel.java index ef2d4c6be8e..78948144c61 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WfHistoryPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WfHistoryPanel.java @@ -42,11 +42,11 @@ public WfHistoryPanel(String id, IModel> model) { @Override protected void initLayout() { - List> columns = new ArrayList>(); + List> columns = new ArrayList<>(); columns.add(new PropertyColumn(createStringResource("WfHistoryPanel.label.timestamp"), WfHistoryEventDto.F_TIMESTAMP_FORMATTED)); columns.add(new PropertyColumn(createStringResource("WfHistoryPanel.label.event"), WfHistoryEventDto.F_EVENT)); ISortableDataProvider provider = new ListDataProvider(this, getModel()); - add(new TablePanel(ID_HISTORY_TABLE, provider, columns)); + add(new TablePanel<>(ID_HISTORY_TABLE, provider, columns)); } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsTablePanel.html similarity index 100% rename from gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsPanel.html rename to gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsTablePanel.html diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsTablePanel.java similarity index 59% rename from gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsPanel.java rename to gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsTablePanel.java index ec3f385ad52..a10d0eab7cb 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsPanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/WorkItemsTablePanel.java @@ -20,20 +20,18 @@ import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.web.component.data.BoxedTablePanel; import com.evolveum.midpoint.web.component.data.TablePanel; +import com.evolveum.midpoint.web.component.data.column.CheckBoxHeaderColumn; import com.evolveum.midpoint.web.component.data.column.LinkColumn; -import com.evolveum.midpoint.web.component.util.ListDataProvider; -import com.evolveum.midpoint.web.page.admin.home.dto.MyWorkItemDto; import com.evolveum.midpoint.web.page.admin.workflow.PageWorkItem; +import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDtoProvider; import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDto; +import com.evolveum.midpoint.web.session.UserProfileStorage; import com.evolveum.midpoint.web.util.OnePageParameterEncoder; - import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; -import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; -import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; -import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider; -import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.*; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.AbstractReadOnlyModel; @@ -47,33 +45,38 @@ * @author lazyman * @author mederly */ -public class WorkItemsPanel extends BasePanel> { +public class WorkItemsTablePanel extends BasePanel { private static final String ID_WORK_ITEMS_TABLE = "workItemsTable"; - public WorkItemsPanel(String id, IModel> model) { - super(id, model); - initLayout(true); - } + private ISortableDataProvider provider; - public WorkItemsPanel(String id, IModel> model, boolean showAssigned) { - super(id, model); - initLayout(showAssigned); + public WorkItemsTablePanel(String id, ISortableDataProvider provider, + UserProfileStorage.TableId tableId, int pageSize, boolean showAssigned) { + super(id); + this.provider = provider; + initLayout(tableId, pageSize, showAssigned); } // this is called locally in order to take showAssigned into account - private void initLayout(boolean showAssigned) { - List> columns = new ArrayList>(); + private void initLayout(UserProfileStorage.TableId tableId, int pageSize, boolean showAssigned) { + List> columns = new ArrayList<>(); + + // TODO configurable + columns.add(new CheckBoxHeaderColumn()); + + // TODO clickable links and info icons + columns.add(new PropertyColumn(createStringResource("WorkItemsPanel.object"), WorkItemDto.F_OBJECT_NAME)); + columns.add(new PropertyColumn(createStringResource("WorkItemsPanel.target"), WorkItemDto.F_TARGET_NAME)); + if (WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_WORK_ITEMS_ALL_URL, AuthorizationConstants.AUTZ_UI_WORK_ITEM_URL)) { - columns.add(new LinkColumn(createStringResource("WorkItemsPanel.name"), MyWorkItemDto.F_NAME, MyWorkItemDto.F_NAME) { - + columns.add(new LinkColumn(createStringResource("WorkItemsPanel.name"), WorkItemDto.F_NAME, WorkItemDto.F_NAME) { @Override public void onClick(AjaxRequestTarget target, IModel rowModel) { - WorkItemDto workItemDto = rowModel.getObject(); PageParameters parameters = new PageParameters(); - parameters.add(OnePageParameterEncoder.PARAMETER, workItemDto.getWorkItem().getWorkItemId()); - setResponsePage(new PageWorkItem(parameters, (PageBase) WorkItemsPanel.this.getPage())); + parameters.add(OnePageParameterEncoder.PARAMETER, rowModel.getObject().getWorkItemId()); + setResponsePage(new PageWorkItem(parameters, (PageBase) WorkItemsTablePanel.this.getPage())); } }); } else { @@ -82,25 +85,41 @@ public void onClick(AjaxRequestTarget target, IModel rowModel) { public void populateItem(Item> item, String componentId, final IModel rowModel) { item.add(new Label(componentId, new AbstractReadOnlyModel() { - @Override public Object getObject() { - WorkItemDto dto = rowModel.getObject(); - return dto.getName(); + return rowModel.getObject().getName(); } })); } }); } - + columns.add(new PropertyColumn(createStringResource("WorkItemsPanel.started"), WorkItemDto.F_PROCESS_STARTED)); + columns.add(new PropertyColumn(createStringResource("WorkItemsPanel.created"), WorkItemDto.F_CREATED)); if (showAssigned) { - columns.add(new PropertyColumn(createStringResource("WorkItemsPanel.assigned"), WorkItemDto.F_OWNER_OR_CANDIDATES)); + columns.add(new PropertyColumn(createStringResource("WorkItemsPanel.assigned"), WorkItemDto.F_ASSIGNEE_OR_CANDIDATES)); } - columns.add(new PropertyColumn(createStringResource("WorkItemsPanel.created"), WorkItemDto.F_CREATED)); - ISortableDataProvider provider = new ListDataProvider(this, getModel()); - TablePanel accountsTable = new TablePanel(ID_WORK_ITEMS_TABLE, provider, columns); - add(accountsTable); + BoxedTablePanel workItemsTable = new BoxedTablePanel<>(ID_WORK_ITEMS_TABLE, provider, columns, tableId, pageSize); + add(workItemsTable); + } + + private TablePanel getWorkItemTable() { + return (TablePanel) get(ID_WORK_ITEMS_TABLE); } + + public List getSelectedWorkItems() { + DataTable table = getWorkItemTable().getDataTable(); + WorkItemDtoProvider provider = (WorkItemDtoProvider) table.getDataProvider(); + + List selected = new ArrayList<>(); + for (WorkItemDto row : provider.getAvailableData()) { + if (row.isSelected()) { + selected.add(row); + } + } + + return selected; + } + } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalHistoryPanel.html similarity index 67% rename from gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalPanel.html rename to gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalHistoryPanel.html index b22b14e4372..739ead3fdf2 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalPanel.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalHistoryPanel.html @@ -17,17 +17,6 @@ -

...

- - -

- - -

- -

-
- diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalHistoryPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalHistoryPanel.java new file mode 100644 index 00000000000..8a8651a6cd9 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalHistoryPanel.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010-2013 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.component.wf.processes.itemApproval; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.component.wf.DecisionsPanel; +import com.evolveum.midpoint.web.page.admin.workflow.dto.DecisionDto; +import com.evolveum.midpoint.xml.ns._public.common.common_3.DecisionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ItemApprovalProcessStateType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author mederly + */ +public class ItemApprovalHistoryPanel extends BasePanel { + + private static final Trace LOGGER = TraceManager.getTrace(ItemApprovalHistoryPanel.class); + + private static final String ID_DECISIONS_DONE = "decisionsDone"; + + public ItemApprovalHistoryPanel(String id, IModel model) { + super(id, model); + initLayout(); + } + + private void initLayout() { + + add(new DecisionsPanel(ID_DECISIONS_DONE, new AbstractReadOnlyModel>() { + @Override + public List getObject() { + List rv = new ArrayList<>(); + WfContextType wfContextType = getModelObject(); + if (wfContextType == null) { + return rv; + } + ItemApprovalProcessStateType instanceState = (ItemApprovalProcessStateType) wfContextType.getProcessSpecificState(); + List allDecisions = instanceState.getDecisions(); + if (allDecisions == null) { + return rv; + } + for (DecisionType decision : allDecisions) { + rv.add(new DecisionDto(decision)); + } + return rv; + } + })); + + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalPanel.java deleted file mode 100644 index c9bc840c72c..00000000000 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/component/wf/processes/itemApproval/ItemApprovalPanel.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.web.component.wf.processes.itemApproval; - -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; -import com.evolveum.midpoint.web.component.wf.DecisionsPanel; -import com.evolveum.midpoint.web.component.wf.WorkItemsPanel; -import com.evolveum.midpoint.web.page.admin.workflow.dto.DecisionDto; -import com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceDto; -import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDto; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalLevelType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalSchemaType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.DecisionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ItemApprovalProcessState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ItemApprovalRequestType; - -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.commons.lang.Validate; -import org.apache.wicket.AttributeModifier; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.panel.Panel; -import org.apache.wicket.model.AbstractReadOnlyModel; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.PropertyModel; -import org.apache.wicket.model.ResourceModel; -import org.apache.wicket.model.StringResourceModel; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author mederly - */ -public class ItemApprovalPanel extends Panel { - - private static final Trace LOGGER = TraceManager.getTrace(ItemApprovalPanel.class); - - private static final String ID_ITEM_TO_BE_APPROVED_LABEL = "itemToBeApprovedLabel"; - private static final String ID_ITEM_TO_BE_APPROVED = "itemToBeApproved"; - //private static final String ID_RESULT = "result"; - - private static final String ID_APPROVAL_SCHEMA = "approvalSchema"; - - private static final String ID_DECISIONS_DONE_LABEL = "decisionsDoneLabel"; - private static final String ID_DECISIONS_DONE = "decisionsDone"; - - private static final String ID_CURRENT_WORK_ITEMS = "currentWorkItems"; - private static final String ID_CURRENT_WORK_ITEMS_LABEL = "currentWorkItemsLabel"; - - private IModel model; - - public ItemApprovalPanel(String id, IModel model) { - super(id); - Validate.notNull(model); - this.model = model; - - initLayout(); - } - - private void initLayout() { - - Label itemToBeApprovedLabel = new Label(ID_ITEM_TO_BE_APPROVED_LABEL, new StringResourceModel("${}", new AbstractReadOnlyModel() { - @Override - public String getObject() { - if (!model.getObject().isAnswered()) { - return "ItemApprovalPanel.itemToBeApproved"; - } else { - Boolean result = model.getObject().getAnswerAsBoolean(); - if (result == null) { - return "ItemApprovalPanel.itemThatWasCompleted"; // actually, this should not happen, if the process is ItemApproval - } else if (result) { - return "ItemApprovalPanel.itemThatWasApproved"; - } else { - return "ItemApprovalPanel.itemThatWasRejected"; - } - } - } - })); - itemToBeApprovedLabel.add(new AttributeModifier("color", new AbstractReadOnlyModel() { - @Override - public String getObject() { - if (!model.getObject().isAnswered()) { - return "black"; // should not be visible, anyway - } else { - Boolean result = model.getObject().getAnswerAsBoolean(); - if (result == null) { - return "black"; // actually, this should not happen, if the process is ItemApproval - } else if (result) { - return "green"; - } else { - return "red"; - } - } - } - })); - add(itemToBeApprovedLabel); - - Label itemToBeApproved = new Label(ID_ITEM_TO_BE_APPROVED, new AbstractReadOnlyModel() { - - @Override - public String getObject() { - - ItemApprovalProcessState instanceState = (ItemApprovalProcessState) model.getObject().getInstanceState().getProcessSpecificState(); - ItemApprovalRequestType approvalRequestType = instanceState.getApprovalRequest(); - - if (approvalRequestType == null) { - return "?"; - } else { - Object item = approvalRequestType.getItemToApprove(); - if (item instanceof AssignmentType) { - AssignmentType assignmentType = (AssignmentType) item; - if (assignmentType.getTarget() != null) { - return assignmentType.getTarget().toString(); - } else if (assignmentType.getTargetRef() != null) { - return assignmentType.getTargetRef().getOid() + " (" + assignmentType.getTargetRef().getType() + ")"; - } else { - return "?"; - } - } else { - return item != null ? item.toString() : "(none)"; - } - } - } - }); - add(itemToBeApproved); - - // todo i18n - Label approvalSchema = new Label(ID_APPROVAL_SCHEMA, new AbstractReadOnlyModel() { - @Override - public Object getObject() { - StringBuilder retval = new StringBuilder(); - - ItemApprovalProcessState instanceState = (ItemApprovalProcessState) model.getObject().getInstanceState().getProcessSpecificState(); - ItemApprovalRequestType approvalRequestType = instanceState.getApprovalRequest(); - - if (approvalRequestType == null) { - return "?"; - } else { - ApprovalSchemaType approvalSchema = approvalRequestType.getApprovalSchema(); - if (approvalSchema != null) { - if (approvalSchema.getName() != null) { - retval.append(""); - retval.append(StringEscapeUtils.escapeHtml(approvalSchema.getName())); - retval.append(""); - } - if (approvalSchema.getDescription() != null) { - retval.append(" ("); - retval.append(StringEscapeUtils.escapeHtml(approvalSchema.getDescription())); - retval.append(")"); - } - if (approvalSchema.getName() != null || approvalSchema.getDescription() != null) { - retval.append("
"); - } - retval.append("Levels:

    "); - for (ApprovalLevelType level : approvalSchema.getLevel()) { - retval.append("
  1. "); - if (level.getName() != null) { - retval.append(StringEscapeUtils.escapeHtml(level.getName())); - } else { - retval.append("unnamed level"); - } - if (level.getDescription() != null) { - retval.append(" ("); - retval.append(StringEscapeUtils.escapeHtml(level.getDescription())); - retval.append(")"); - } - if (level.getEvaluationStrategy() != null) { - retval.append(" [" + level.getEvaluationStrategy() + "]"); - } - if (level.getAutomaticallyApproved() != null) { - String desc = level.getAutomaticallyApproved().getDescription(); - if (desc != null) { - retval.append(" (auto-approval condition: " + StringEscapeUtils.escapeHtml(desc) + ")"); - } else { - retval.append(" (auto-approval condition present)"); - } - } - retval.append("
    Approvers:
      "); - for (ObjectReferenceType approverRef : level.getApproverRef()) { - retval.append("
    • "); - retval.append(approverRef.getOid()); - if (approverRef.getType() != null) { - retval.append(" (" + approverRef.getType().getLocalPart() + ")"); - } - if (approverRef.getDescription() != null) { - retval.append (" - " + approverRef.getDescription()); - } - retval.append("
    • "); - } - for (ExpressionType expression : level.getApproverExpression()) { - retval.append("
    • Expression: "); - // todo display the expression - if (expression.getDescription() != null) { - retval.append(StringEscapeUtils.escapeHtml(expression.getDescription())); - } else { - retval.append("(...)"); - } - retval.append("
    • "); - } - } - - retval.append("
    "); // ends the list of approvers - retval.append("
"); // ends the list of levels - } - } - return retval.toString(); - } - }); - approvalSchema.setEscapeModelStrings(false); - add(approvalSchema); - - add(new Label(ID_DECISIONS_DONE_LABEL, new StringResourceModel("ItemApprovalPanel.decisionsDoneWhenFinishedIs_${finished}", model))); - - add(new DecisionsPanel(ID_DECISIONS_DONE, new AbstractReadOnlyModel>() { - @Override - public List getObject() { - List retval = new ArrayList<>(); - ProcessInstanceDto processInstanceDto = model.getObject(); - processInstanceDto.reviveIfNeeded(ItemApprovalPanel.this); - ItemApprovalProcessState instanceState = (ItemApprovalProcessState) processInstanceDto.getInstanceState().getProcessSpecificState(); - List allDecisions = instanceState.getDecisions(); - if (allDecisions != null) { - for (DecisionType decision : allDecisions) { - retval.add(new DecisionDto(decision)); - } - } - return retval; - } - })); - - VisibleEnableBehaviour visibleIfRunning = new VisibleEnableBehaviour() { - @Override - public boolean isVisible() { - return !model.getObject().isFinished(); - } - }; - - Label workItemsPanelLabel = new Label(ID_CURRENT_WORK_ITEMS_LABEL, new ResourceModel("ItemApprovalPanel.currentWorkItems")); - workItemsPanelLabel.add(visibleIfRunning); - add(workItemsPanelLabel); - - WorkItemsPanel workItemsPanel = new WorkItemsPanel(ID_CURRENT_WORK_ITEMS, new PropertyModel>(model, "workItems")); - workItemsPanel.add(visibleIfRunning); - add(workItemsPanel); - } -} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminFocus.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminFocus.java index f4fecf50291..11a4bddc18f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminFocus.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminFocus.java @@ -24,6 +24,7 @@ import javax.xml.namespace.QName; +import com.evolveum.midpoint.web.component.prism.show.PagePreviewChanges; import org.apache.commons.lang.StringUtils; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; @@ -184,6 +185,12 @@ protected ObjectWrapper loadFocusWrapper(PrismObject userToEdit) { @Override public void finishProcessing(AjaxRequestTarget target, OperationResult result) { + + if (previewRequested) { + finishPreviewProcessing(target, result); + return; + } + boolean userAdded = getDelta() != null && getDelta().isAdd() && StringUtils.isNotEmpty(getDelta().getOid()); if (!isKeepDisplayingResults() && getProgressReporter().isAllSuccess() && (userAdded || !result.isFatalError())) { // TODO @@ -201,7 +208,7 @@ public void finishProcessing(AjaxRequestTarget target, OperationResult result) { } } - goBackPage(); + redirectBack(); } else { getProgressReporter().showBackButton(target); getProgressReporter().hideAbortButton(target); @@ -220,6 +227,13 @@ public void finishProcessing(AjaxRequestTarget target, OperationResult result) { } } + private void finishPreviewProcessing(AjaxRequestTarget target, OperationResult result) { + showResult(result); + target.add(getFeedbackPanel()); + setResponsePage(new PagePreviewChanges(getProgressReporter().getPreviewResult(), getModelInteractionService(), this)); + // TODO implement "back" functionality correctly + } + private List loadShadowWrappers() { return loadProjectionWrappers(ShadowType.class, UserType.F_LINK_REF); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminObjectDetails.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminObjectDetails.java index fdf95e0a42f..c478de23f11 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminObjectDetails.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/PageAdminObjectDetails.java @@ -21,6 +21,7 @@ import javax.xml.namespace.QName; +import com.evolveum.midpoint.model.api.context.ModelContext; import org.apache.commons.lang.StringUtils; import org.apache.wicket.Page; import org.apache.wicket.RestartResponseException; @@ -86,6 +87,7 @@ public abstract class PageAdminObjectDetails extends PageA private static final String OPERATION_LOAD_PARENT_ORGS = DOT_CLASS + "loadParentOrgs"; private static final String OPERATION_LOAD_GUI_CONFIGURATION = DOT_CLASS + "loadGuiConfiguration"; protected static final String OPERATION_SAVE = DOT_CLASS + "save"; + protected static final String OPERATION_PREVIEW_CHANGES = DOT_CLASS + "previewChanges"; protected static final String OPERATION_SEND_TO_SUBMIT = DOT_CLASS + "sendToSubmit"; protected static final String ID_SUMMARY_PANEL = "summaryPanel"; @@ -377,12 +379,27 @@ public Object findParam(String param, String oid, OperationResult result) { return object; } + // TODO put this into correct place + protected boolean previewRequested; + /** * This will be called from the main form when save button is pressed. */ public void savePerformed(AjaxRequestTarget target) { progressReporter.onSaveSubmit(); OperationResult result = new OperationResult(OPERATION_SAVE); + previewRequested = false; + saveOrPreviewPerformed(target, result, false); + } + + public void previewPerformed(AjaxRequestTarget target) { + progressReporter.onSaveSubmit(); + OperationResult result = new OperationResult(OPERATION_PREVIEW_CHANGES); + previewRequested = true; + saveOrPreviewPerformed(target, result, true); + } + + public void saveOrPreviewPerformed(AjaxRequestTarget target, OperationResult result, boolean previewOnly) { ObjectWrapper objectWrapper = getObjectWrapper(); LOGGER.debug("Saving object {}", objectWrapper); @@ -429,22 +446,12 @@ public void savePerformed(AjaxRequestTarget target) { if (!delta.isEmpty()) { delta.revive(getPrismContext()); - Collection validationErrors = performCustomValidation(objectToAdd, - WebComponentUtil.createDeltaCollection(delta)); - if (validationErrors != null && !validationErrors.isEmpty()) { - for (SimpleValidationError error : validationErrors) { - LOGGER.error("Validation error, attribute: '" + error.printAttribute() - + "', message: '" + error.getMessage() + "'."); - error("Validation error, attribute: '" + error.printAttribute() - + "', message: '" + error.getMessage() + "'."); - } - - target.add(getFeedbackPanel()); + final Collection> deltas = WebComponentUtil.createDeltaCollection(delta); + final Collection validationErrors = performCustomValidation(objectToAdd, deltas); + if (checkValidationErrors(target, validationErrors)) { return; } - - progressReporter.executeChanges(WebComponentUtil.createDeltaCollection(delta), options, - task, result, target); + progressReporter.executeChanges(deltas, previewOnly, options, task, result, target); } else { result.recordSuccess(); } @@ -484,37 +491,17 @@ public void savePerformed(AjaxRequestTarget target) { objectWrapper.getObject().getOid(), getPrismContext()); deltas.add(emptyDelta); - Collection validationErrors = performCustomValidation(null, - deltas); - if (validationErrors != null && !validationErrors.isEmpty()) { - for (SimpleValidationError error : validationErrors) { - LOGGER.error("Validation error, attribute: '" + error.printAttribute() - + "', message: '" + error.getMessage() + "'."); - error("Validation error, attribute: '" + error.printAttribute() - + "', message: '" + error.getMessage() + "'."); - } - - target.add(getFeedbackPanel()); + Collection validationErrors = performCustomValidation(null, deltas); + if (checkValidationErrors(target, validationErrors)) { return; } - - progressReporter.executeChanges(deltas, options, task, result, target); + progressReporter.executeChanges(deltas, previewOnly, options, task, result, target); } else if (!deltas.isEmpty()) { - Collection validationErrors = performCustomValidation(null, - deltas); - if (validationErrors != null && !validationErrors.isEmpty()) { - for (SimpleValidationError error : validationErrors) { - LOGGER.error("Validation error, attribute: '" + error.printAttribute() - + "', message: '" + error.getMessage() + "'."); - error("Validation error, attribute: '" + error.printAttribute() - + "', message: '" + error.getMessage() + "'."); - } - - target.add(getFeedbackPanel()); + Collection validationErrors = performCustomValidation(null, deltas); + if (checkValidationErrors(target, validationErrors)) { return; } - - progressReporter.executeChanges(deltas, options, task, result, target); + progressReporter.executeChanges(deltas, previewOnly, options, task, result, target); } else { result.recordSuccess(); } @@ -540,7 +527,22 @@ public void savePerformed(AjaxRequestTarget target) { finishProcessing(target, result); } - LOGGER.trace("returning from savePerformed"); + LOGGER.trace("returning from saveOrPreviewPerformed"); + } + + protected boolean checkValidationErrors(AjaxRequestTarget target, Collection validationErrors) { + if (validationErrors != null && !validationErrors.isEmpty()) { + for (SimpleValidationError error : validationErrors) { + LOGGER.error("Validation error, attribute: '" + error.printAttribute() + + "', message: '" + error.getMessage() + "'."); + error("Validation error, attribute: '" + error.printAttribute() + + "', message: '" + error.getMessage() + "'."); + } + + target.add(getFeedbackPanel()); + return true; + } + return false; } @Override @@ -615,28 +617,6 @@ protected void performAdditionalValidation(PrismObject object, } - // TODO: fix name, confusing. clashes with goBack() - // todo: we should navigate using breadcrumb stack [lazyman] - @Deprecated - public void goBackPage() { - StringValue orgReturn = getPageParameters().get(PARAM_RETURN_PAGE); - if (PageOrgTree.PARAM_ORG_RETURN.equals(orgReturn.toString())) { - setResponsePage(getSessionStorage().getPreviousPage()); - } else if (getPreviousPage() != null) { - goBack(PageDashboard.class); // the class parameter is not necessary, is previousPage is set - } else if (getSessionStorage() != null){ - if (getSessionStorage().getPreviousPageInstance() != null){ - setResponsePage(getSessionStorage().getPreviousPageInstance()); - } else if (getSessionStorage().getPreviousPage() != null){ - setResponsePage(getSessionStorage().getPreviousPage()); - } else { - setResponsePage(getDefaultBackPage()); - } - } else { - setResponsePage(getDefaultBackPage()); - } - } - public abstract PageBase getDefaultBackPage(); public List getObjectFormTypes() { diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.java index e57c6dddaa3..b6b772e9c7f 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/configuration/PageDebugList.java @@ -511,7 +511,7 @@ private void listObjectsPerformed(ObjectQuery query, AjaxRequestTarget target) { if (selected != null) { provider.setType(selected.getClassDefinition()); -// addOrReplaceTable(provider); + addOrReplaceTable(provider); } // save object type category to session storage, used by back button diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/home/dto/MyWorkItemDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/home/dto/MyWorkItemDto.java deleted file mode 100644 index 7b32a8a0879..00000000000 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/home/dto/MyWorkItemDto.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.web.page.admin.home.dto; - -import com.evolveum.midpoint.prism.polystring.PolyString; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; - -import java.io.Serializable; -import java.util.Date; - -/** - * @author lazyman - */ -public class MyWorkItemDto implements Serializable { - - public static final String F_NAME = "name"; - public static final String F_CREATED = "created"; - - private String name; - private Date createdDate; - - public MyWorkItemDto(WorkItemType workItem) { - this.name = PolyString.getOrig(workItem.getName()); - this.createdDate = XmlTypeConverter.toDate(workItem.getMetadata().getCreateTimestamp()); - } - - public Date getCreatedDate() { - return createdDate; - } - - public String getName() { - return name; - } - - public String getCreated() { - //todo use date format - return createdDate != null ? createdDate.toString() : null; - } -} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResources.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResources.html index 3ce5bb5e704..e715823ba81 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResources.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResources.html @@ -21,10 +21,6 @@
-
-
- -

diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResources.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResources.java index 5bdcd7b6b3d..f617a152564 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResources.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/PageResources.java @@ -21,29 +21,19 @@ import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.match.PolyStringNormMatchingRule; -import com.evolveum.midpoint.prism.polystring.PolyStringNormalizer; -import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; -import com.evolveum.midpoint.prism.query.SubstringFilter; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.AuthorizationAction; import com.evolveum.midpoint.web.application.PageDescriptor; -import com.evolveum.midpoint.web.component.BasicSearchPanel; import com.evolveum.midpoint.web.component.data.BaseSortableDataProvider; import com.evolveum.midpoint.web.component.data.BoxedTablePanel; import com.evolveum.midpoint.web.component.data.ObjectDataProvider; @@ -51,20 +41,24 @@ import com.evolveum.midpoint.web.component.data.column.*; import com.evolveum.midpoint.web.component.dialog.ConfirmationDialog; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; +import com.evolveum.midpoint.web.component.search.Search; +import com.evolveum.midpoint.web.component.search.SearchFactory; +import com.evolveum.midpoint.web.component.search.SearchFormPanel; import com.evolveum.midpoint.web.component.util.SelectableBean; import com.evolveum.midpoint.web.page.admin.configuration.PageDebugView; import com.evolveum.midpoint.web.page.admin.configuration.component.HeaderMenuAction; import com.evolveum.midpoint.web.page.admin.resources.component.ContentPanel; import com.evolveum.midpoint.web.page.admin.resources.content.PageContentAccounts; import com.evolveum.midpoint.web.page.admin.resources.content.PageContentEntitlements; -import com.evolveum.midpoint.web.page.admin.resources.dto.*; +import com.evolveum.midpoint.web.page.admin.resources.dto.ResourceController; +import com.evolveum.midpoint.web.page.admin.resources.dto.ResourceDto; +import com.evolveum.midpoint.web.page.admin.resources.dto.ResourceState; import com.evolveum.midpoint.web.page.admin.server.dto.OperationResultStatusIcon; import com.evolveum.midpoint.web.session.ResourcesStorage; import com.evolveum.midpoint.web.session.UserProfileStorage; import com.evolveum.midpoint.web.util.OnePageParameterEncoder; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConnectorHostType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; - import org.apache.commons.lang.StringUtils; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -75,15 +69,14 @@ import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; -import org.apache.wicket.model.PropertyModel; import org.apache.wicket.request.mapper.parameter.PageParameters; import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** @@ -106,19 +99,17 @@ public class PageResources extends PageAdminResources { private static final String OPERATION_DELETE_HOSTS = DOT_CLASS + "deleteHosts"; private static final String OPERATION_CONNECTOR_DISCOVERY = DOT_CLASS + "connectorDiscovery"; - private static final String ID_BASIC_SEARCH = "basicSearch"; - private static final String ID_SEARCH_FORM = "searchForm"; private static final String ID_DELETE_RESOURCES_POPUP = "deleteResourcesPopup"; private static final String ID_DELETE_HOSTS_POPUP = "deleteHostsPopup"; private static final String ID_MAIN_FORM = "mainForm"; private static final String ID_TABLE = "table"; private static final String ID_CONNECTOR_TABLE = "connectorTable"; - private static final String ID_SEARCH_CLEAR = "searchClear"; - private IModel searchModel; + private IModel searchModel; + private IModel chSearchModel; private ResourceDto singleDelete; - public PageResources(){ + public PageResources() { this(true); } @@ -126,44 +117,58 @@ public PageResources(boolean clearSessionPaging) { this(clearSessionPaging, ""); } - public PageResources(String searchText){ + public PageResources(String searchText) { this(true, searchText); } - public PageResources(boolean clearSessionPaging, final String searchText){ - searchModel = new LoadableModel() { + public PageResources(boolean clearSessionPaging, final String searchText) { + getSessionStorage().clearPagingInSession(clearSessionPaging); + + searchModel = new LoadableModel(false) { @Override - protected ResourceSearchDto load() { + protected Search load() { ResourcesStorage storage = getSessionStorage().getResources(); - ResourceSearchDto dto = storage.getResourceSearch(); + Search dto = storage.getResourceSearch(); - if(dto == null){ - dto = new ResourceSearchDto(); - } - if (searchText != null && !searchText.trim().equals("")) { - dto.setText(searchText); + if (dto == null) { + dto = SearchFactory.createSearch(ResourceType.class, getPrismContext(), true); } + return dto; } }; - getSessionStorage().clearPagingInSession(clearSessionPaging); + chSearchModel = new LoadableModel(false) { + + @Override + protected Search load() { + return SearchFactory.createSearch(ConnectorHostType.class, getPrismContext(), true); + } + }; + initLayout(); } private void initLayout() { - Form searchForm = new Form(ID_SEARCH_FORM); - add(searchForm); - searchForm.setOutputMarkupId(true); - initSearchForm(searchForm); - Form mainForm = new Form(ID_MAIN_FORM); add(mainForm); - BoxedTablePanel resources = new BoxedTablePanel<>(ID_TABLE, initResourceDataProvider(), initResourceColumns(), + BoxedTablePanel resources = new BoxedTablePanel(ID_TABLE, initResourceDataProvider(), initResourceColumns(), UserProfileStorage.TableId.PAGE_RESOURCES_PANEL, - (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_RESOURCES_PANEL)); + (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_RESOURCES_PANEL)) { + + @Override + protected WebMarkupContainer createHeader(String headerId) { + return new SearchFormPanel(headerId, searchModel) { + + @Override + protected void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { + PageResources.this.searchPerformed(query, target); + } + }; + } + }; resources.setOutputMarkupId(true); ResourcesStorage storage = getSessionStorage().getResources(); @@ -171,10 +176,22 @@ private void initLayout() { mainForm.add(resources); - BoxedTablePanel connectorHosts = new BoxedTablePanel<>(ID_CONNECTOR_TABLE, + BoxedTablePanel connectorHosts = new BoxedTablePanel(ID_CONNECTOR_TABLE, new ObjectDataProvider(PageResources.this, ConnectorHostType.class), initConnectorHostsColumns(), UserProfileStorage.TableId.PAGE_RESOURCES_CONNECTOR_HOSTS, - (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_RESOURCES_CONNECTOR_HOSTS)); + (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_RESOURCES_CONNECTOR_HOSTS)) { + + @Override + protected WebMarkupContainer createHeader(String headerId) { + return new SearchFormPanel(headerId, chSearchModel) { + + @Override + protected void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { + PageResources.this.searchHostPerformed(query, target); + } + }; + } + }; connectorHosts.setOutputMarkupId(true); mainForm.add(connectorHosts); @@ -203,28 +220,6 @@ public void yesPerformed(AjaxRequestTarget target) { }); } - private void initSearchForm(Form searchForm) { - BasicSearchPanel basicSearch = new BasicSearchPanel(ID_BASIC_SEARCH) { - - @Override - protected IModel createSearchTextModel() { - return new PropertyModel<>(searchModel, ResourceSearchDto.F_TEXT); - } - - @Override - protected void searchPerformed(AjaxRequestTarget target) { - PageResources.this.searchPerformed(target); - } - - @Override - protected void clearSearchPerformed(AjaxRequestTarget target) { - PageResources.this.clearSearchPerformed(target); - } - }; - searchForm.add(basicSearch); - - } - private BaseSortableDataProvider initResourceDataProvider() { ObjectDataProvider provider = new ObjectDataProvider(this, ResourceType.class) { @@ -241,7 +236,7 @@ protected void saveProviderPaging(ObjectQuery query, ObjectPaging paging) { @Override protected void handleNotSuccessOrHandledErrorInIterator(OperationResult result) { - if(result.isPartialError()){ + if (result.isPartialError()) { showResult(result); } else { super.handleNotSuccessOrHandledErrorInIterator(result); @@ -249,13 +244,6 @@ protected void handleNotSuccessOrHandledErrorInIterator(OperationResult result) } }; - //fixes MID-2534; - // connector reference is set in the ResourceDto constructor -// Collection> options = -// SelectorOptions.createCollection(ResourceType.F_CONNECTOR, GetOperationOptions.createResolve()); -// provider.setOptions(options); - provider.setQuery(createQuery()); - return provider; } @@ -272,25 +260,25 @@ public void onClick(AjaxRequestTarget target) { })); dto.getMenuItems().add(new InlineMenuItem(createStringResource("pageResources.inlineMenuItem.deleteSyncToken"), - new ColumnMenuAction(){ + new ColumnMenuAction() { @Override - public void onClick(AjaxRequestTarget target){ + public void onClick(AjaxRequestTarget target) { deleteResourceSyncTokenPerformed(target, getRowModel()); } })); dto.getMenuItems().add(new InlineMenuItem(createStringResource("pageResources.inlineMenuItem.editResource"), - new ColumnMenuAction(){ + new ColumnMenuAction() { @Override - public void onClick(AjaxRequestTarget target){ + public void onClick(AjaxRequestTarget target) { editResourcePerformed(getRowModel()); } })); dto.getMenuItems().add(new InlineMenuItem(createStringResource("pageResources.button.editAsXml"), - new ColumnMenuAction(){ + new ColumnMenuAction() { @Override public void onClick(AjaxRequestTarget target) { @@ -520,7 +508,7 @@ public String getObject() { Table table = resources ? getResourceTable() : getConnectorHostTable(); List selected = new ArrayList(); - if(singleDelete != null){ + if (singleDelete != null) { selected.add(singleDelete); } else { selected = WebComponentUtil.getSelectedData(table); @@ -572,7 +560,7 @@ private void deleteHostConfirmedPerformed(AjaxRequestTarget target) { private void deleteResourceConfirmedPerformed(AjaxRequestTarget target) { List selected = new ArrayList<>(); - if(singleDelete != null){ + if (singleDelete != null) { selected.add(singleDelete); } else { selected = WebComponentUtil.getSelectedData(getResourceTable()); @@ -664,34 +652,19 @@ private void testResourcePerformed(AjaxRequestTarget target, IModel } } - private ObjectQuery createQuery() { - ResourceSearchDto dto = searchModel.getObject(); - ObjectQuery query = null; - String searchText = dto.getText(); - - if(StringUtils.isEmpty(dto.getText())) { - return null; - } - - try{ - PolyStringNormalizer normalizer = getPrismContext().getDefaultPolyStringNormalizer(); - String normalizedString = normalizer.normalize(searchText); - - ObjectFilter substring = SubstringFilter.createSubstring(ResourceType.F_NAME, ResourceType.class, - getPrismContext(), PolyStringNormMatchingRule.NAME, normalizedString); - query = new ObjectQuery(); - query.setFilter(substring); + private void searchHostPerformed(ObjectQuery query, AjaxRequestTarget target) { + target.add(getFeedbackPanel()); - } catch (Exception e) { - error(getString("pageResources.message.queryError") + " " + e.getMessage()); - LoggingUtils.logException(LOGGER, "Couldn't create query filter.", e); - } + Table panel = getConnectorHostTable(); + DataTable table = panel.getDataTable(); + ObjectDataProvider provider = (ObjectDataProvider) table.getDataProvider(); + provider.setQuery(query); + provider.setOptions(SelectorOptions.createCollection(GetOperationOptions.createNoFetch())); - return query; + target.add((Component) panel); } - private void searchPerformed(AjaxRequestTarget target) { - ObjectQuery query = createQuery(); + private void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { target.add(getFeedbackPanel()); Table panel = getResourceTable(); @@ -711,32 +684,16 @@ private void deleteResourceSyncTokenPerformed(AjaxRequestTarget target, IModel model){ + private void editResourcePerformed(IModel model) { PageParameters parameters = new PageParameters(); parameters.add(OnePageParameterEncoder.PARAMETER, model.getObject().getOid()); setResponsePage(new PageResourceWizard(parameters)); } - private void editAsXmlPerformed(IModel model){ + private void editAsXmlPerformed(IModel model) { PageParameters parameters = new PageParameters(); parameters.add(PageDebugView.PARAM_OBJECT_ID, model.getObject().getOid()); parameters.add(PageDebugView.PARAM_OBJECT_TYPE, ResourceType.class.getSimpleName()); setResponsePage(PageDebugView.class, parameters); } - - private void clearSearchPerformed(AjaxRequestTarget target){ - searchModel.setObject(new ResourceSearchDto()); - - Table panel = getResourceTable(); - DataTable table = panel.getDataTable(); - ObjectDataProvider provider = (ObjectDataProvider) table.getDataProvider(); - provider.setQuery(null); - - ResourcesStorage storage = getSessionStorage().getResources(); - storage.setResourceSearch(searchModel.getObject()); - panel.setCurrentPage(storage.getResourcePaging()); - - target.add(get(ID_SEARCH_FORM)); - target.add((Component) panel); - } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java index 04dfb8bc38d..742d73ca082 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRole.java @@ -197,7 +197,6 @@ protected AbstractObjectMainPanel createMainPanel(String id) { @Override public PageBase getDefaultBackPage() { - return new PageRoles(false, ""); + return new PageRoles(false); } - } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRoles.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRoles.html index 3e6435079d9..290a8bc1701 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRoles.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/roles/PageRoles.html @@ -24,17 +24,6 @@
- -
-
- - - - -
-
- +
+

diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItem.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItem.java index 063945a7a43..f50b9d36439 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItem.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItem.java @@ -17,18 +17,18 @@ import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.gui.api.page.PageBase; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.model.api.WorkflowService; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.polystring.PolyString; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.builder.QueryBuilder; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; @@ -37,40 +37,26 @@ import com.evolveum.midpoint.web.application.PageDescriptor; import com.evolveum.midpoint.web.component.AjaxButton; import com.evolveum.midpoint.web.component.AjaxSubmitButton; -import com.evolveum.midpoint.web.component.accordion.Accordion; -import com.evolveum.midpoint.web.component.accordion.AccordionItem; -import com.evolveum.midpoint.web.component.model.delta.ContainerValuePanel; -import com.evolveum.midpoint.web.component.model.delta.DeltaDto; -import com.evolveum.midpoint.web.component.model.delta.DeltaPanel; -import com.evolveum.midpoint.web.component.prism.ContainerStatus; -import com.evolveum.midpoint.web.component.prism.ObjectWrapper; -import com.evolveum.midpoint.web.component.prism.PrismObjectPanel; -import com.evolveum.midpoint.web.component.util.ObjectWrapperUtil; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; -import com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceDto; -import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDetailedDto; +import com.evolveum.midpoint.web.page.admin.home.PageDashboard; import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDto; -import com.evolveum.midpoint.web.resource.img.ImgResources; import com.evolveum.midpoint.web.util.OnePageParameterEncoder; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessInstanceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.GeneralChangeApprovalWorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; - -import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.Form; -import org.apache.wicket.markup.html.panel.Panel; -import org.apache.wicket.model.*; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; import org.apache.wicket.request.mapper.parameter.PageParameters; -import org.apache.wicket.request.resource.PackageResourceReference; import org.springframework.security.core.context.SecurityContextHolder; +import java.util.Collection; +import java.util.List; + +import static com.evolveum.midpoint.schema.GetOperationOptions.resolveItemsNamed; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_WORKFLOW_CONTEXT; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType.F_REQUESTER_REF; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType.*; + /** * @author mederly */ @@ -90,39 +76,13 @@ public class PageWorkItem extends PageAdminWorkItems { private static final String OPERATION_CLAIM_WORK_ITEM = DOT_CLASS + "claimWorkItem"; private static final String OPERATION_RELEASE_WORK_ITEM = DOT_CLASS + "releaseWorkItem"; - private static final String ID_ACCORDION = "accordion"; - private static final String ID_DELTA_PANEL = "deltaPanel"; + private static final String ID_WORK_ITEM_PANEL = "workItemPanel"; private static final Trace LOGGER = TraceManager.getTrace(PageWorkItem.class); - private static final String ID_DELTA_INFO = "deltaInfo"; - - private static final String ID_REQUESTER_ACCORDION_INFO = "requesterAccordionInfo"; - private static final String ID_REQUESTER_PANEL = "requesterPanel"; - private static final String ID_OBJECT_OLD_ACCORDION_INFO = "objectOldAccordionInfo"; - private static final String ID_OBJECT_OLD_PANEL = "objectOldPanel"; - private static final String ID_OBJECT_NEW_ACCORDION_INFO = "objectNewAccordionInfo"; - private static final String ID_OBJECT_NEW_PANEL = "objectNewPanel"; - private static final String ID_ADDITIONAL_DATA_ACCORDION_INFO = "additionalDataAccordionInfo"; - private static final String ID_ADDITIONAL_DATA_PANEL = "additionalDataPanel"; - private static final String ID_PROCESS_INSTANCE_ACCORDION_INFO = "processInstanceAccordionInfo"; - private static final String ID_PROCESS_INSTANCE_PANEL = "processInstancePanel"; - private static final String ID_SHOW_TECHNICAL_INFORMATION = "showTechnicalInformation"; private PageParameters parameters; - private IModel workItemDtoModel; - - private IModel requesterModel; - private IModel objectOldModel; - private IModel objectNewModel; - private IModel> requestSpecificModel; - private IModel> additionalDataModel; - private IModel trackingDataModel; - private LoadableModel processInstanceDtoModel; - private IModel deltaModel; - - private IModel showTechnicalInformationModel = new Model(); - private Accordion additionalInfoAccordion; + private LoadableModel workItemDtoModel; public PageWorkItem() { this(new PageParameters(), null); @@ -138,61 +98,12 @@ public PageWorkItem(PageParameters parameters, PageBase previousPage, boolean re setPreviousPage(previousPage); setReinitializePreviousPages(reinitializePreviousPage); - requesterModel = new LoadableModel(false) { + workItemDtoModel = new LoadableModel(false) { @Override - protected ObjectWrapper load() { - loadWorkItemDetailedDtoIfNecessary(); - return getRequesterWrapper(); + protected WorkItemDto load() { + return loadWorkItemDtoIfNecessary(); } }; - objectOldModel = new LoadableModel(false) { - @Override - protected ObjectWrapper load() { - loadWorkItemDetailedDtoIfNecessary(); - return getObjectOldWrapper(); - } - }; - objectNewModel = new LoadableModel(false) { - @Override - protected ObjectWrapper load() { - loadWorkItemDetailedDtoIfNecessary(); - return getObjectNewWrapper(); - } - }; - requestSpecificModel = new LoadableModel>(false) { - @Override - protected ObjectWrapper load() { - loadWorkItemDetailedDtoIfNecessary(); - return getRequestSpecificWrapper(); - } - }; - additionalDataModel = new LoadableModel>(false) { - @Override - protected ObjectWrapper load() { - loadWorkItemDetailedDtoIfNecessary(); - return getAdditionalDataWrapper(); - } - }; - trackingDataModel = new LoadableModel(false) { - @Override - protected ObjectWrapper load() { - loadWorkItemDetailedDtoIfNecessary(); - return getTrackingDataWrapper(); - } - }; - workItemDtoModel = new LoadableModel(false) { - @Override - protected WorkItemDetailedDto load() { - return loadWorkItemDetailedDtoIfNecessary(); - } - }; - processInstanceDtoModel = new LoadableModel(false) { - @Override - protected ProcessInstanceDto load() { - return loadProcessInstanceDto(); - } - }; - deltaModel = new PropertyModel(workItemDtoModel, WorkItemDetailedDto.F_DELTA); initLayout(); } @@ -208,224 +119,39 @@ protected String load() { }; } - private ObjectWrapper getRequesterWrapper() { - PrismObject prism = workItemDtoModel.getObject().getWorkItem().getRequester().asPrismObject(); - - ContainerStatus status = ContainerStatus.MODIFYING; - ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( - createStringResource("pageWorkItem.requester.description").getString(), // name (large font) - PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) - prism, status, true, this); - wrapper.setShowEmpty(false); - wrapper.setMinimalized(true); - wrapper.setShowAssignments(false); - wrapper.setReadonly(true); - wrapper.initializeContainers(this); - showResult(wrapper.getResult(), false); - - return wrapper; - - } - - private ObjectWrapper getObjectOldWrapper() { - GeneralChangeApprovalWorkItemContents wic = getGeneralChangeApprovalWorkItemContents(); - ObjectType objectOld = wic.getObjectOld(); - - PrismObject prism; - if (objectOld != null) { - prism = objectOld.asPrismObject(); - } else { - prism = createEmptyUserObject(); - } - - ContainerStatus status = ContainerStatus.MODIFYING; - ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( - createStringResource("pageWorkItem.objectOld.description").getString(), // name (large font) - PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) - prism, status, true, this); - wrapper.setShowEmpty(false); - wrapper.setMinimalized(true); - wrapper.setShowAssignments(true); - wrapper.setReadonly(true); - wrapper.initializeContainers(this); - showResult(wrapper.getResult(), false); - - return wrapper; - - } - - private GeneralChangeApprovalWorkItemContents getGeneralChangeApprovalWorkItemContents() { - ObjectType contents = workItemDtoModel.getObject().getWorkItem().getContents(); - if (contents instanceof GeneralChangeApprovalWorkItemContents) { - return (GeneralChangeApprovalWorkItemContents) contents; - } else { - return null; - } - } - - private ObjectWrapper getObjectNewWrapper() { - GeneralChangeApprovalWorkItemContents wic = getGeneralChangeApprovalWorkItemContents(); - ObjectType objectNew = wic.getObjectNew(); - - PrismObject prism; - if (objectNew != null) { - prism = objectNew.asPrismObject(); - } else { - prism = createEmptyUserObject(); - } - - ContainerStatus status = ContainerStatus.MODIFYING; - ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( - createStringResource("pageWorkItem.objectNew.description").getString(), // name (large font) - PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) - prism, status, true, this); - wrapper.setShowEmpty(false); - wrapper.setMinimalized(true); - wrapper.setShowAssignments(true); - wrapper.setReadonly(true); - wrapper.initializeContainers(this); - showResult(wrapper.getResult(), false); - - return wrapper; - } - - - private PrismObject createEmptyUserObject() { - PrismObject p = new PrismObject(UserType.COMPLEX_TYPE, UserType.class); - try { - getPrismContext().adopt(p); - } catch (SchemaException e) { // safe to convert; this should not occur - throw new SystemException("Got schema exception when creating empty user object.", e); - } - return p; - } - - private ObjectWrapper getRequestSpecificWrapper() { - GeneralChangeApprovalWorkItemContents wic = getGeneralChangeApprovalWorkItemContents(); - PrismObject prism = wic.getQuestionForm().asPrismObject(); - - ContainerStatus status = ContainerStatus.MODIFYING; - try{ - ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper("pageWorkItem.requestSpecifics", null, prism, status, true, this); - wrapper.setShowEmpty(true); - wrapper.setMinimalized(false); - wrapper.setShowInheritedObjectAttributes(false); - wrapper.initializeContainers(this); - showResult(wrapper.getResult(), false); - - return wrapper; - } catch (Exception ex){ - throw new SystemException("Got schema exception when creating general change approval work item contents.", ex); - } - } - - private ObjectWrapper getAdditionalDataWrapper() { - GeneralChangeApprovalWorkItemContents wic = getGeneralChangeApprovalWorkItemContents(); - ObjectType relatedObject = wic.getRelatedObject(); - PrismObject prism; - if (relatedObject != null) { - prism = relatedObject.asPrismObject(); - } else { - prism = createEmptyUserObject(); // not quite correct, but ... ok - } - - ContainerStatus status = ContainerStatus.MODIFYING; - try { - ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper( - createStringResource("pageWorkItem.additionalData.description").getString(), // name (large font) - PolyString.getOrig(prism.asObjectable().getName()), // description (smaller font) - prism, status, true, this); - wrapper.setShowEmpty(false); - wrapper.setMinimalized(true); - wrapper.setReadonly(true); - wrapper.initializeContainers(this); - showResult(wrapper.getResult(), false); - return wrapper; - } catch (Exception ex){ - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get work item.", ex); - } - return null; - - } - - private ObjectWrapper getTrackingDataWrapper() { - PrismObject prism = workItemDtoModel.getObject().getWorkItem().getTrackingData().asPrismObject(); - - ContainerStatus status = ContainerStatus.MODIFYING; - try { - ObjectWrapper wrapper = ObjectWrapperUtil.createObjectWrapper("pageWorkItem.trackingData", null, - prism, status, true, this); - wrapper.setShowEmpty(false); - wrapper.setMinimalized(true); - wrapper.setReadonly(true); - wrapper.initializeContainers(this); - wrapper.setShowInheritedObjectAttributes(false); - showResult(wrapper.getResult(), false); - - return wrapper; - } catch (Exception ex) { - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get work item.", ex); - } - return null; - } - - private WorkItemDetailedDto loadWorkItemDetailedDtoIfNecessary() { - - if (((LoadableModel) workItemDtoModel).isLoaded()) { + private WorkItemDto loadWorkItemDtoIfNecessary() { + if (workItemDtoModel.isLoaded()) { return workItemDtoModel.getObject(); } - - OperationResult result = new OperationResult(OPERATION_LOAD_WORK_ITEM); - WorkItemDetailedDto workItemDetailedDto = null; - WorkItemType workItem = null; + Task task = createSimpleTask(OPERATION_LOAD_WORK_ITEM); + OperationResult result = task.getResult(); + WorkItemDto workItemDto = null; try { - WorkflowService wfm = getWorkflowService(); - workItem = wfm.getWorkItemDetailsById(parameters.get(OnePageParameterEncoder.PARAMETER).toString(), result); - workItemDetailedDto = new WorkItemDetailedDto(workItem, getPrismContext()); + String id = parameters.get(OnePageParameterEncoder.PARAMETER).toString(); + final ObjectQuery query = QueryBuilder.queryFor(WorkItemType.class, getPrismContext()) + .item(F_WORK_ITEM_ID).eq(id) + .build(); + final Collection> options = resolveItemsNamed( + F_ASSIGNEE_REF, + new ItemPath(F_TASK_REF, F_WORKFLOW_CONTEXT, F_REQUESTER_REF)); + List workItems = getModelService().searchContainers(WorkItemType.class, query, options, task, result); + if (workItems.size() > 1) { + throw new SystemException("More than one work item with ID of " + id); + } else if (workItems.size() == 0) { + throw new SystemException("No work item with ID of " + id); + } + workItemDto = new WorkItemDto(workItems.get(0)); + workItemDto.prepareDeltaVisualization("pageWorkItem.delta", getPrismContext(), getModelInteractionService(), task, result); result.recordSuccessIfUnknown(); } catch (Exception ex) { result.recordFatalError("Couldn't get work item.", ex); LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get work item.", ex); } - - - showResult(result, false); + showResult(result, false); if (!result.isSuccess()) { - throw getRestartResponseException(PageWorkItems.class); - } - - return workItemDetailedDto; - } - - private ProcessInstanceDto loadProcessInstanceDto() { - OperationResult result = new OperationResult(OPERATION_LOAD_PROCESS_INSTANCE); - WfProcessInstanceType processInstance; - try { - String taskId = parameters.get(OnePageParameterEncoder.PARAMETER).toString(); - LOGGER.trace("Loading process instance for task {}", taskId); - WorkflowService wfm = getWorkflowService(); - processInstance = wfm.getProcessInstanceByWorkItemId(taskId, result); - LOGGER.trace("Found process instance {}", processInstance); - String shadowTaskOid = ((ProcessInstanceState) processInstance.getState()).getShadowTaskOid(); - Task shadowTask = null; - try { - shadowTask = getTaskManager().getTask(shadowTaskOid, result); - } catch (ObjectNotFoundException e) { - // ok - } - result.recordSuccess(); - return new ProcessInstanceDto(processInstance, shadowTask); - } catch (ObjectNotFoundException ex) { - result.recordWarning("Work item seems to be already closed."); - LoggingUtils.logException(LOGGER, "Couldn't get process instance for work item; it might be already closed.", ex); - showResult(result); - throw getRestartResponseException(PageWorkItems.class); - } catch (Exception ex) { - result.recordFatalError("Couldn't get process instance for work item.", ex); - LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get process instance for work item.", ex); - showResult(result); - throw getRestartResponseException(PageWorkItems.class); + throw getRestartResponseException(PageDashboard.class); } + return workItemDto; } private void initLayout() { @@ -433,175 +159,11 @@ private void initLayout() { mainForm.setMultiPart(true); add(mainForm); - Label requestedBy = new Label("requestedBy", new PropertyModel(requesterModel, "object.asObjectable.name")); - mainForm.add(requestedBy); - - Label requestedByFullName = new Label("requestedByFullName", new PropertyModel(requesterModel, "object.asObjectable.fullName")); - mainForm.add(requestedByFullName); - - Label requestedOn = new Label("requestedOn", new AbstractReadOnlyModel() { - - @Override - public String getObject() { - ProcessInstanceDto dto = processInstanceDtoModel.getObject(); - if (dto.getProcessInstance().getStartTimestamp() == null) { - return ""; - } - return WebComponentUtil.formatDate(XmlTypeConverter.toDate(dto.getProcessInstance().getStartTimestamp())); - } - - }); - mainForm.add(requestedOn); - - Label workItemCreatedOn = new Label("workItemCreatedOn", new AbstractReadOnlyModel() { - - @Override - public String getObject() { - WorkItemDetailedDto dto = workItemDtoModel.getObject(); - if (dto.getWorkItem().getMetadata() == null || dto.getWorkItem().getMetadata().getCreateTimestamp() == null) { - return ""; - } - return WebComponentUtil.formatDate(XmlTypeConverter.toDate(dto.getWorkItem().getMetadata().getCreateTimestamp())); - } - - }); - mainForm.add(workItemCreatedOn); - - Label assignee = new Label("assignee", new PropertyModel(workItemDtoModel, WorkItemDto.F_ASSIGNEE)); - mainForm.add(assignee); - - Label candidates = new Label("candidates", new PropertyModel(workItemDtoModel, WorkItemDto.F_CANDIDATES)); - mainForm.add(candidates); - - PrismObjectPanel requestSpecificForm = new PrismObjectPanel("requestSpecificForm", requestSpecificModel, - new PackageResourceReference(ImgResources.class, ImgResources.DECISION_PRISM), mainForm, this) { - - @Override - protected IModel createDisplayName(IModel> model) { - return createStringResource("pageWorkItem.requestSpecific.description"); - } - - @Override - protected IModel createDescription(IModel> model) { - return new Model<>(""); - } - }; - mainForm.add(requestSpecificForm); - - additionalInfoAccordion = new Accordion(ID_ACCORDION); - additionalInfoAccordion.setOutputMarkupId(true); - additionalInfoAccordion.setMultipleSelect(true); - additionalInfoAccordion.setExpanded(false); - mainForm.add(additionalInfoAccordion); - - PrismObjectPanel requesterForm = new PrismObjectPanel("requesterForm", requesterModel, - new PackageResourceReference(ImgResources.class, ImgResources.USER_PRISM), mainForm, this); - requesterForm.add(new VisibleEnableBehaviour() { - @Override - public boolean isVisible() { - return requesterModel != null && !requesterModel.getObject().getObject().isEmpty(); - } - }); - mainForm.add(requesterForm); - - PrismObjectPanel objectOldForm = new PrismObjectPanel("objectOldForm", objectOldModel, - new PackageResourceReference(ImgResources.class, ImgResources.USER_PRISM), mainForm, this); - objectOldForm.add(new VisibleEnableBehaviour() { - @Override - public boolean isVisible() { - return getGeneralChangeApprovalWorkItemContents() != null && getGeneralChangeApprovalWorkItemContents().getObjectOld() != null; - } - }); - mainForm.add(objectOldForm); - - PrismObjectPanel objectNewForm = new PrismObjectPanel("objectNewForm", objectNewModel, - new PackageResourceReference(ImgResources.class, ImgResources.USER_PRISM), mainForm, this); - objectNewForm.add(new VisibleEnableBehaviour() { - @Override - public boolean isVisible() { - return getGeneralChangeApprovalWorkItemContents() != null && getGeneralChangeApprovalWorkItemContents().getObjectNew() != null; - } - }); - mainForm.add(objectNewForm); - - PrismObjectPanel additionalDataForm = new PrismObjectPanel("additionalDataForm", additionalDataModel, - new PackageResourceReference(ImgResources.class, ImgResources.ROLE_PRISM), mainForm, this); - mainForm.add(additionalDataForm); - - PrismObjectPanel trackingDataForm = new PrismObjectPanel("trackingDataForm", trackingDataModel, - new PackageResourceReference(ImgResources.class, ImgResources.TRACKING_PRISM), mainForm, this) { - - @Override - protected IModel createDisplayName(IModel model) { - return createStringResource("pageWorkItem.trackingData.description"); - } - - @Override - protected IModel createDescription(IModel model) { - return new Model(""); - } - }; - mainForm.add(trackingDataForm); - - - AccordionItem deltaInfo = new AccordionItem(ID_DELTA_INFO, new ResourceModel("pageWorkItem.delta")); - deltaInfo.setOutputMarkupId(true); - additionalInfoAccordion.getBodyContainer().add(deltaInfo); - - DeltaPanel deltaPanel = new DeltaPanel(ID_DELTA_PANEL, deltaModel); - deltaInfo.getBodyContainer().add(deltaPanel); + mainForm.add(new WorkItemPanel(ID_WORK_ITEM_PANEL, workItemDtoModel, this)); - additionalInfoAccordion.getBodyContainer().add(createObjectAccordionItem(ID_REQUESTER_ACCORDION_INFO, ID_REQUESTER_PANEL, "pageWorkItem.accordionLabel.requester", new PropertyModel(workItemDtoModel, WorkItemDetailedDto.F_REQUESTER), true)); - additionalInfoAccordion.getBodyContainer().add(createObjectAccordionItem(ID_OBJECT_OLD_ACCORDION_INFO, ID_OBJECT_OLD_PANEL, "pageWorkItem.accordionLabel.objectOld", new PropertyModel(workItemDtoModel, WorkItemDetailedDto.F_OBJECT_OLD), true)); - additionalInfoAccordion.getBodyContainer().add(createObjectAccordionItem(ID_OBJECT_NEW_ACCORDION_INFO, ID_OBJECT_NEW_PANEL, "pageWorkItem.accordionLabel.objectNew", new PropertyModel(workItemDtoModel, WorkItemDetailedDto.F_OBJECT_NEW), true)); - additionalInfoAccordion.getBodyContainer().add(createObjectAccordionItem(ID_ADDITIONAL_DATA_ACCORDION_INFO, ID_ADDITIONAL_DATA_PANEL, "pageWorkItem.accordionLabel.additionalData", new PropertyModel(workItemDtoModel, WorkItemDetailedDto.F_RELATED_OBJECT), true)); - - LOGGER.trace("processInstanceDtoModel = {}, loaded = {}", processInstanceDtoModel, processInstanceDtoModel.isLoaded()); - ProcessInstanceDto processInstanceDto = processInstanceDtoModel.getObject(); - WfProcessInstanceType processInstance = processInstanceDto.getProcessInstance(); - additionalInfoAccordion.getBodyContainer().add(createAccordionItem(ID_PROCESS_INSTANCE_ACCORDION_INFO, - "pageWorkItem.accordionLabel.processInstance", - new ProcessInstancePanel(ID_PROCESS_INSTANCE_PANEL, processInstanceDtoModel), true)); initButtons(mainForm); } - private Component createAccordionItem(String idAccordionInfo, String key, Panel panel, boolean isTechnical) { - AccordionItem info = new AccordionItem(idAccordionInfo, new ResourceModel(key)); - info.setOutputMarkupId(true); - info.getBodyContainer().add(panel); - - if (isTechnical) { - info.add(new VisibleEnableBehaviour() { - - @Override - public boolean isVisible() { - return Boolean.TRUE.equals(showTechnicalInformationModel.getObject()); - } - }); - } - - return info; - } - - private Component createObjectAccordionItem(String idAccordionInfo, String idPanel, String key, IModel model, boolean isTechnical) { - AccordionItem info = new AccordionItem(idAccordionInfo, new ResourceModel(key)); - info.setOutputMarkupId(true); - ContainerValuePanel panel = new ContainerValuePanel(idPanel, model); - info.getBodyContainer().add(panel); - - if (isTechnical) { - info.add(new VisibleEnableBehaviour() { - @Override - public boolean isVisible() { - return Boolean.TRUE.equals(showTechnicalInformationModel.getObject()); - } - }); - } - - return info; - } - - private void initButtons(Form mainForm) { VisibleEnableBehaviour isAllowedToSubmit = new VisibleEnableBehaviour() { @@ -697,26 +259,6 @@ protected void onError(AjaxRequestTarget target, Form form) { reject.add(isAllowedToSubmit); mainForm.add(reject); -// AjaxSubmitLinkButton done = new AjaxSubmitLinkButton("done", -// createStringResource("pageWorkItem.button.done")) { -// -// @Override -// protected void onSubmit(AjaxRequestTarget target, Form form) { -// try { -// savePerformed(target); -// } catch(RuntimeException e) { -// LoggingUtils.logException(LOGGER, "Exception in savePerformed", e); -// throw e; -// } -// } -// -// @Override -// protected void onError(AjaxRequestTarget target, Form form) { -// target.add(getFeedbackPanel()); -// } -// }; -// mainForm.add(done); - AjaxButton cancel = new AjaxButton("cancel", createStringResource("pageWorkItem.button.cancel")) { @Override @@ -725,16 +267,6 @@ public void onClick(AjaxRequestTarget target) { } }; mainForm.add(cancel); - - CheckBox showTechnicalInformationBox = new CheckBox(ID_SHOW_TECHNICAL_INFORMATION, showTechnicalInformationModel); - showTechnicalInformationBox.add(new AjaxFormComponentUpdatingBehavior("change") { - - @Override - protected void onUpdate(AjaxRequestTarget target) { - target.add(additionalInfoAccordion); - } - }); - mainForm.add(showTechnicalInformationBox); } private void cancelPerformed(AjaxRequestTarget target) { @@ -747,13 +279,8 @@ private void savePerformed(AjaxRequestTarget target, boolean decision) { OperationResult result = new OperationResult(OPERATION_SAVE_WORK_ITEM); try { - reviveModels(); - ObjectWrapper rsWrapper = requestSpecificModel.getObject(); - PrismObject object = rsWrapper.getObject(); - ObjectDelta delta = rsWrapper.getObjectDelta(); - delta.applyTo(object); - - getWorkflowService().approveOrRejectWorkItemWithDetails(workItemDtoModel.getObject().getWorkItem().getWorkItemId(), object, decision, result); + WorkItemDto dto = workItemDtoModel.getObject(); + getWorkflowService().approveOrRejectWorkItem(dto.getWorkItemId(), decision, dto.getApproverComment(), result); setReinitializePreviousPages(true); } catch (Exception ex) { result.recordFatalError("Couldn't save work item.", ex); @@ -776,9 +303,9 @@ private void claimPerformed(AjaxRequestTarget target) { OperationResult result = new OperationResult(OPERATION_CLAIM_WORK_ITEM); WorkflowService workflowService = getWorkflowService(); try { - workflowService.claimWorkItem(workItemDtoModel.getObject().getWorkItem().getWorkItemId(), result); + workflowService.claimWorkItem(workItemDtoModel.getObject().getWorkItemId(), result); setReinitializePreviousPages(true); - } catch (RuntimeException e) { + } catch (SecurityViolationException | ObjectNotFoundException | RuntimeException e) { result.recordFatalError("Couldn't claim work item due to an unexpected exception.", e); } result.computeStatusIfUnknown(); @@ -799,7 +326,7 @@ private void releasePerformed(AjaxRequestTarget target) { try { workflowService.releaseWorkItem(workItemDtoModel.getObject().getWorkItem().getWorkItemId(), result); setReinitializePreviousPages(true); - } catch (RuntimeException e) { + } catch (SecurityViolationException | ObjectNotFoundException | RuntimeException e) { result.recordFatalError("Couldn't release work item due to an unexpected exception.", e); } result.computeStatusIfUnknown(); @@ -818,13 +345,4 @@ public PageBase reinitialize() { return new PageWorkItem(parameters, getPreviousPage(), true); } - private void reviveModels() throws SchemaException { - WebComponentUtil.revive(requesterModel, getPrismContext()); - WebComponentUtil.revive(objectOldModel, getPrismContext()); - WebComponentUtil.revive(objectNewModel, getPrismContext()); - WebComponentUtil.revive(requestSpecificModel, getPrismContext()); - WebComponentUtil.revive(trackingDataModel, getPrismContext()); - WebComponentUtil.revive(additionalDataModel, getPrismContext()); - } - } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItems.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItems.html index 5d56e914b38..4b21bbe0906 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItems.html +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItems.html @@ -19,7 +19,7 @@ -
+
diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItems.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItems.java index 2bce3492f78..dc538e45c49 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItems.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/PageWorkItems.java @@ -16,40 +16,24 @@ package com.evolveum.midpoint.web.page.admin.workflow; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.model.api.WorkflowService; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.AuthorizationAction; import com.evolveum.midpoint.web.application.PageDescriptor; import com.evolveum.midpoint.web.component.AjaxButton; -import com.evolveum.midpoint.web.component.data.TablePanel; -import com.evolveum.midpoint.web.component.data.column.CheckBoxHeaderColumn; -import com.evolveum.midpoint.web.component.data.column.LinkColumn; -import com.evolveum.midpoint.web.page.admin.workflow.dto.*; +import com.evolveum.midpoint.web.component.wf.WorkItemsTablePanel; +import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDtoProvider; +import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDto; import com.evolveum.midpoint.web.session.UserProfileStorage; -import com.evolveum.midpoint.web.util.OnePageParameterEncoder; -import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; - import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; -import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; -import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable; -import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; -import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; -import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Form; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.model.AbstractReadOnlyModel; -import org.apache.wicket.model.IModel; -import org.apache.wicket.request.mapper.parameter.PageParameters; -import java.util.ArrayList; -import java.util.Date; import java.util.List; /** @@ -73,6 +57,10 @@ public class PageWorkItems extends PageAdminWorkItems { private static final String OPERATION_CLAIM_ITEM = DOT_CLASS + "claimItem"; private static final String OPERATION_RELEASE_ITEMS = DOT_CLASS + "releaseItems"; private static final String OPERATION_RELEASE_ITEM = DOT_CLASS + "releaseItem"; + private static final String ID_WORK_ITEMS_PANEL = "workItemsPanel"; + + private static final String ID_MAIN_FORM = "mainForm"; + private static final String ID_WORK_ITEM_TABLE = "workItemTable"; boolean assigned; @@ -87,60 +75,16 @@ public PageWorkItems(boolean assigned) { } private void initLayout() { - Form mainForm = new Form("mainForm"); + Form mainForm = new Form(ID_MAIN_FORM); add(mainForm); - List> workItemColumns = initWorkItemColumns(); - TablePanel workItemTable = new TablePanel<>("workItemTable", new WorkItemDtoProvider(PageWorkItems.this, assigned), - workItemColumns, UserProfileStorage.TableId.PAGE_WORK_ITEMS, getItemsPerPage(UserProfileStorage.TableId.PAGE_WORK_ITEMS)); - workItemTable.setOutputMarkupId(true); - mainForm.add(workItemTable); - - initItemButtons(mainForm); - } - - private List> initWorkItemColumns() { - List> columns = new ArrayList<>(); - - IColumn column = new CheckBoxHeaderColumn(); - columns.add(column); - - column = new LinkColumn(createStringResource("pageWorkItems.item.name"), "name", "name") { - - @Override - public void onClick(AjaxRequestTarget target, IModel rowModel) { - WorkItemDto workItemDto = rowModel.getObject(); - itemDetailsPerformed(target, workItemDto.getWorkItem().getWorkItemId()); - } - }; - columns.add(column); - - columns.add(new AbstractColumn(createStringResource("pageWorkItems.item.created")) { + WorkItemsTablePanel panel = new WorkItemsTablePanel(ID_WORK_ITEMS_PANEL, new WorkItemDtoProvider(PageWorkItems.this, assigned), + UserProfileStorage.TableId.PAGE_WORK_ITEMS, (int) getItemsPerPage(UserProfileStorage.TableId.PAGE_WORK_ITEMS), true); - @Override - public void populateItem(Item> item, String componentId, - final IModel rowModel) { - item.add(new Label(componentId, new AbstractReadOnlyModel() { - - @Override - public Object getObject() { - WorkItemDto pi = rowModel.getObject(); - Date started = XmlTypeConverter.toDate(pi.getWorkItem().getMetadata().getCreateTimestamp()); - if (started == null) { - return "?"; - } else { - return WebComponentUtil.formatDate(started); - } - } - })); - } - }); - - if (!assigned) { - columns.add(new PropertyColumn(createStringResource("pageWorkItems.item.candidates"), WorkItemDto.F_CANDIDATES)); - } + panel.setOutputMarkupId(true); + mainForm.add(panel); - return columns; + initItemButtons(mainForm); } private void initItemButtons(Form mainForm) { @@ -186,24 +130,6 @@ public void onClick(AjaxRequestTarget target) { mainForm.add(reject); } - private TablePanel getWorkItemTable() { - return (TablePanel) get("mainForm:workItemTable"); - } - - private List getSelectedWorkItems() { - DataTable table = getWorkItemTable().getDataTable(); - WorkItemDtoProvider provider = (WorkItemDtoProvider) table.getDataProvider(); - - List selected = new ArrayList(); - for (WorkItemDto row : provider.getAvailableData()) { - if (row.isSelected()) { - selected.add(row); - } - } - - return selected; - } - private boolean isSomeItemSelected(List items, AjaxRequestTarget target) { if (!items.isEmpty()) { return true; @@ -214,14 +140,12 @@ private boolean isSomeItemSelected(List items, AjaxRequestTarget ta return false; } - private void itemDetailsPerformed(AjaxRequestTarget target, String taskid) { - PageParameters parameters = new PageParameters(); - parameters.add(OnePageParameterEncoder.PARAMETER, taskid); - setResponsePage(new PageWorkItem(parameters, this)); + private WorkItemsTablePanel getWorkItemsPanel() { + return (WorkItemsTablePanel) get(ID_WORK_ITEMS_PANEL); } private void approveOrRejectWorkItemsPerformed(AjaxRequestTarget target, boolean approve) { - List workItemDtoList = getSelectedWorkItems(); + List workItemDtoList = getWorkItemsPanel().getSelectedWorkItems(); if (!isSomeItemSelected(workItemDtoList, target)) { return; } @@ -231,7 +155,7 @@ private void approveOrRejectWorkItemsPerformed(AjaxRequestTarget target, boolean for (WorkItemDto workItemDto : workItemDtoList) { OperationResult result = mainResult.createSubresult(OPERATION_APPROVE_OR_REJECT_ITEM); try { - workflowService.approveOrRejectWorkItem(workItemDto.getWorkItem().getWorkItemId(), approve, result); + workflowService.approveOrRejectWorkItem(workItemDto.getWorkItemId(), approve, null, result); result.computeStatus(); } catch (Exception e) { result.recordPartialError("Couldn't approve/reject work item due to an unexpected exception.", e); @@ -247,13 +171,12 @@ private void approveOrRejectWorkItemsPerformed(AjaxRequestTarget target, boolean showResult(mainResult); - //refresh feedback and table target.add(getFeedbackPanel()); - target.add(getWorkItemTable()); + target.add(getWorkItemsPanel()); } private void claimWorkItemsPerformed(AjaxRequestTarget target) { - List workItemDtoList = getSelectedWorkItems(); + List workItemDtoList = getWorkItemsPanel().getSelectedWorkItems(); if (!isSomeItemSelected(workItemDtoList, target)) { return; } @@ -263,9 +186,9 @@ private void claimWorkItemsPerformed(AjaxRequestTarget target) { for (WorkItemDto workItemDto : workItemDtoList) { OperationResult result = mainResult.createSubresult(OPERATION_CLAIM_ITEM); try { - workflowService.claimWorkItem(workItemDto.getWorkItem().getWorkItemId(), result); + workflowService.claimWorkItem(workItemDto.getWorkItemId(), result); result.computeStatusIfUnknown(); - } catch (RuntimeException e) { + } catch (ObjectNotFoundException | SecurityViolationException | RuntimeException e) { result.recordPartialError("Couldn't claim work item due to an unexpected exception.", e); } } @@ -279,13 +202,12 @@ private void claimWorkItemsPerformed(AjaxRequestTarget target) { showResult(mainResult); - //refresh feedback and table target.add(getFeedbackPanel()); - target.add(getWorkItemTable()); + target.add(getWorkItemsPanel()); } private void releaseWorkItemsPerformed(AjaxRequestTarget target) { - List workItemDtoList = getSelectedWorkItems(); + List workItemDtoList = getWorkItemsPanel().getSelectedWorkItems(); if (!isSomeItemSelected(workItemDtoList, target)) { return; } @@ -295,9 +217,9 @@ private void releaseWorkItemsPerformed(AjaxRequestTarget target) { for (WorkItemDto workItemDto : workItemDtoList) { OperationResult result = mainResult.createSubresult(OPERATION_RELEASE_ITEM); try { - workflowService.releaseWorkItem(workItemDto.getWorkItem().getWorkItemId(), result); + workflowService.releaseWorkItem(workItemDto.getWorkItemId(), result); result.computeStatusIfUnknown(); - } catch (RuntimeException e) { + } catch (ObjectNotFoundException | SecurityViolationException | RuntimeException e) { result.recordPartialError("Couldn't release work item due to an unexpected exception.", e); } } @@ -311,8 +233,7 @@ private void releaseWorkItemsPerformed(AjaxRequestTarget target) { showResult(mainResult); - //refresh feedback and table target.add(getFeedbackPanel()); - target.add(getWorkItemTable()); + target.add(getWorkItemsPanel()); } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/ProcessInstancePanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/ProcessInstancePanel.java index e9330220584..3d0692e84f3 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/ProcessInstancePanel.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/ProcessInstancePanel.java @@ -17,132 +17,120 @@ package com.evolveum.midpoint.web.page.admin.workflow; import com.evolveum.midpoint.gui.api.component.BasePanel; -import com.evolveum.midpoint.gui.api.page.PageBase; -import com.evolveum.midpoint.util.logging.LoggingUtils; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.web.component.data.column.LinkPanel; -import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; -import com.evolveum.midpoint.web.component.wf.processes.EmptyProcessDetailsPanel; -import com.evolveum.midpoint.web.component.wf.processes.itemApproval.ItemApprovalPanel; -import com.evolveum.midpoint.web.page.admin.server.PageTaskEdit; -import com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceDto; -import com.evolveum.midpoint.web.util.OnePageParameterEncoder; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ItemApprovalProcessState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; - -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.panel.Panel; +import com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceNewDto; import org.apache.wicket.model.IModel; -import org.apache.wicket.model.PropertyModel; -import org.apache.wicket.request.mapper.parameter.PageParameters; - -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; - -public class ProcessInstancePanel extends BasePanel { - - private static final Trace LOGGER = TraceManager.getTrace(ProcessInstancePanel.class); - - private static final String ID_DETAILS = "details"; - private static final String ID_TASK = "task"; - private static final String ID_TASK_COMMENT = "taskComment"; - private static Map,Class> panelsForProcesses = null; - - public static void registerProcessInstancePanel(Class dataClass, Class panelClass) { - if (panelsForProcesses == null) { - panelsForProcesses = new HashMap<>(); - } - panelsForProcesses.put(dataClass, panelClass); - } - - // TODO it would be nicer if individual panels could register themselves - static { - registerProcessInstancePanel(ItemApprovalProcessState.class, ItemApprovalPanel.class); - registerProcessInstancePanel(ProcessSpecificState.class, EmptyProcessDetailsPanel.class); +public class ProcessInstancePanel extends BasePanel { + public ProcessInstancePanel(String id) { + super(id); } - public ProcessInstancePanel(String id, IModel model) { + public ProcessInstancePanel(String id, IModel model) { super(id, model); - initLayoutLocal(); } - private void initLayoutLocal() { - final IModel model = getModel(); - - Label name = new Label("name", new PropertyModel(model, "name")); - add(name); - - Label pid = new Label("pid", new PropertyModel(model, "instanceId")); - add(pid); - - Label started = new Label("started", new PropertyModel(model, "startedTime")); - add(started); - - Label finished = new Label("finished", new PropertyModel(model, "finishedTime")); - add(finished); - - // todo disable clicking behaviour if task does not exist - LinkPanel task = new LinkPanel(ID_TASK, new PropertyModel(model, ProcessInstanceDto.F_SHADOW_TASK)) { - @Override - public void onClick(AjaxRequestTarget target) { - String oid = model.getObject().getShadowTaskOid(); - if (oid != null) { - PageParameters parameters = new PageParameters(); - parameters.add(OnePageParameterEncoder.PARAMETER, oid); - setResponsePage(new PageTaskEdit(parameters, (PageBase) this.getPage())); - } - } - - @Override - public boolean isEnabled() { - return model.getObject().isShadowTaskExisting(); - } - }; - add(task); - - Label taskComment = new Label(ID_TASK_COMMENT, createStringResource("processInstancePanel.taskAlreadyRemoved")); - taskComment.add(new VisibleEnableBehaviour() { - @Override - public boolean isVisible() { - return !model.getObject().isShadowTaskExisting(); - } - }); - add(taskComment); - - try { - Class panelClass = getDetailsPanelClassName(); - Panel detailsPanel = panelClass.getConstructor(String.class, IModel.class).newInstance(ID_DETAILS, model); - add(detailsPanel); - } catch (InvocationTargetException|InstantiationException|NoSuchMethodException|IllegalAccessException|RuntimeException e) { - LoggingUtils.logException(LOGGER, "Details panel couldn't be shown", e); - Label problemLabel = new Label(ID_DETAILS, "Details cannot be shown because of the following exception: " + e.getMessage() + ". Please see the log for more details"); - add(problemLabel); - } - } - - private Class getDetailsPanelClassName() { - ProcessInstanceDto processInstanceDto = getModel().getObject(); - ProcessSpecificState processSpecificState = ((ProcessInstanceState) processInstanceDto.getProcessInstance().getState()).getProcessSpecificState(); - if (processSpecificState != null) { - Class dataClass = processSpecificState.getClass(); - while (dataClass != null) { - Class panelClass = panelsForProcesses.get(dataClass); - if (panelClass != null) { - return panelClass; - } else { - dataClass = (Class) dataClass.getSuperclass(); - } - } - throw new IllegalStateException("A panel for displaying workflow process state of type " + processInstanceDto.getProcessInstance().getState().getClass() + " couldn't be found"); - } else { - return EmptyProcessDetailsPanel.class; - } - } + // private static final Trace LOGGER = TraceManager.getTrace(ProcessInstancePanel.class); +// +// private static final String ID_DETAILS = "details"; +// private static final String ID_TASK = "task"; +// private static final String ID_TASK_COMMENT = "taskComment"; +// public static final String ID_NAME = "name"; +// public static final String ID_PID = "pid"; +// public static final String ID_STARTED = "started"; +// public static final String ID_FINISHED = "finished"; +// +// private static Map,Class> panelsForProcesses = null; +// +// public static void registerProcessInstancePanel(Class dataClass, Class panelClass) { +// if (panelsForProcesses == null) { +// panelsForProcesses = new HashMap<>(); +// } +// panelsForProcesses.put(dataClass, panelClass); +// } +// +// // TODO it would be nicer if individual panels could register themselves +// static { +//// registerProcessInstancePanel(ItemApprovalProcessState.class, ItemApprovalPanel.class); +// registerProcessInstancePanel(ProcessSpecificState.class, EmptyProcessDetailsPanel.class); +// } +// +// public ProcessInstancePanel(String id, IModel model) { +// super(id, model); +// initLayoutLocal(); +// } +// +// private void initLayoutLocal() { +// final IModel model = getModel(); +// +// Label name = new Label(ID_NAME, new PropertyModel(model, "name")); +// add(name); +// +// Label pid = new Label(ID_PID, new PropertyModel(model, "instanceId")); +// add(pid); +// +// Label started = new Label(ID_STARTED, new PropertyModel(model, "startedTime")); +// add(started); +// +// Label finished = new Label(ID_FINISHED, new PropertyModel(model, "finishedTime")); +// add(finished); +// +// // todo disable clicking behaviour if task does not exist +// LinkPanel task = new LinkPanel(ID_TASK, new PropertyModel(model, ProcessInstanceDto.F_SHADOW_TASK)) { +// @Override +// public void onClick(AjaxRequestTarget target) { +// String oid = model.getObject().getShadowTaskOid(); +// if (oid != null) { +// PageParameters parameters = new PageParameters(); +// parameters.add(OnePageParameterEncoder.PARAMETER, oid); +// setResponsePage(new PageTaskEdit(parameters, (PageBase) this.getPage())); +// } +// } +// +// @Override +// public boolean isEnabled() { +// return model.getObject().isShadowTaskExisting(); +// } +// }; +// add(task); +// +// Label taskComment = new Label(ID_TASK_COMMENT, createStringResource("processInstancePanel.taskAlreadyRemoved")); +// taskComment.add(new VisibleEnableBehaviour() { +// @Override +// public boolean isVisible() { +// return !model.getObject().isShadowTaskExisting(); +// } +// }); +// add(taskComment); +// +// try { +// Class panelClass = getDetailsPanelClassName(); +// Panel detailsPanel = panelClass.getConstructor(String.class, IModel.class).newInstance(ID_DETAILS, model); +// add(detailsPanel); +// } catch (InvocationTargetException|InstantiationException|NoSuchMethodException|IllegalAccessException|RuntimeException e) { +// LoggingUtils.logUnexpectedException(LOGGER, "Details panel couldn't be shown", e); +// Label problemLabel = new Label(ID_DETAILS, "Details cannot be shown because of the following exception: " + e.getMessage() + ". Please see the log for more details"); +// add(problemLabel); +// } +// } +// +// private Class getDetailsPanelClassName() { +// ProcessInstanceNewDto processInstanceDto = getModel().getObject(); +// ProcessSpecificState processSpecificState = ((ProcessInstanceState) processInstanceDto.getProcessInstance().getState()).getProcessSpecificState(); +// if (processSpecificState != null) { +// Class dataClass = processSpecificState.getClass(); +// while (dataClass != null) { +// Class panelClass = panelsForProcesses.get(dataClass); +// if (panelClass != null) { +// return panelClass; +// } else { +// dataClass = (Class) dataClass.getSuperclass(); +// } +// } +// throw new IllegalStateException("A panel for displaying workflow process state of type " + processInstanceDto.getProcessInstance().getState().getClass() + " couldn't be found"); +// } else { +// return EmptyProcessDetailsPanel.class; +// } +// } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkItemPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkItemPanel.html new file mode 100644 index 00000000000..c9db99110ad --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkItemPanel.html @@ -0,0 +1,60 @@ + + + + + + + +

+ + + + + + + + + + + + + + + + + + + + + +
()
+ +

+
+ +

+
+ +

+ + + +

+ + + \ No newline at end of file diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkItemPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkItemPanel.java new file mode 100644 index 00000000000..cf015c4fc44 --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkItemPanel.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.web.page.admin.workflow; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.gui.api.page.PageBase; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.web.component.prism.show.ScenePanel; +import com.evolveum.midpoint.web.component.wf.processes.itemApproval.ItemApprovalHistoryPanel; +import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDto; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.TextArea; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; + +/** + * @author mederly + */ +public class WorkItemPanel extends BasePanel { + + private static final Trace LOGGER = TraceManager.getTrace(WorkItemPanel.class); + + private static final String ID_REQUESTED_BY = "requestedBy"; + private static final String ID_REQUESTED_BY_FULL_NAME = "requestedByFullName"; + private static final String ID_REQUESTED_ON = "requestedOn"; + private static final String ID_WORK_ITEM_CREATED_ON = "workItemCreatedOn"; + private static final String ID_ASSIGNEE = "assignee"; + private static final String ID_CANDIDATES = "candidates"; + private static final String ID_DELTAS_TO_BE_APPROVED = "deltasToBeApproved"; + private static final String ID_HISTORY = "history"; + private static final String ID_APPROVER_COMMENT = "approverComment"; + + public WorkItemPanel(String id, IModel model, PageBase pageBase) { + super(id, model); + initLayout(pageBase); + } + + protected void initLayout(PageBase pageBase) { + add(new Label(ID_REQUESTED_BY, new PropertyModel(getModel(), WorkItemDto.F_REQUESTER_NAME))); + add(new Label(ID_REQUESTED_BY_FULL_NAME, new PropertyModel(getModel(), WorkItemDto.F_REQUESTER_FULL_NAME))); + add(new Label(ID_REQUESTED_ON, new PropertyModel(getModel(), WorkItemDto.F_PROCESS_STARTED))); + add(new Label(ID_WORK_ITEM_CREATED_ON, new PropertyModel(getModel(), WorkItemDto.F_CREATED))); + add(new Label(ID_ASSIGNEE, new PropertyModel(getModel(), WorkItemDto.F_ASSIGNEE))); + add(new Label(ID_CANDIDATES, new PropertyModel(getModel(), WorkItemDto.F_CANDIDATES))); + add(new ItemApprovalHistoryPanel(ID_HISTORY, new PropertyModel(getModel(), WorkItemDto.F_WORKFLOW_CONTEXT))); + add(new ScenePanel(ID_DELTAS_TO_BE_APPROVED, new PropertyModel(getModel(), WorkItemDto.F_DELTAS))); + add(new TextArea(ID_APPROVER_COMMENT, new PropertyModel(getModel(), WorkItemDto.F_APPROVER_COMMENT))); + } + +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/component/MyRequestsPanel.html b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkflowRequestsPanel.html similarity index 100% rename from gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/component/MyRequestsPanel.html rename to gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkflowRequestsPanel.html diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkflowRequestsPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkflowRequestsPanel.java new file mode 100644 index 00000000000..39e1fad18fa --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/WorkflowRequestsPanel.java @@ -0,0 +1,130 @@ +package com.evolveum.midpoint.web.page.admin.workflow; + +import com.evolveum.midpoint.gui.api.component.BasePanel; +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.security.api.AuthorizationConstants; +import com.evolveum.midpoint.web.component.data.BoxedTablePanel; +import com.evolveum.midpoint.web.component.data.TablePanel; +import com.evolveum.midpoint.web.component.data.column.CheckBoxHeaderColumn; +import com.evolveum.midpoint.web.component.data.column.IconColumn; +import com.evolveum.midpoint.web.component.data.column.LinkColumn; +import com.evolveum.midpoint.web.page.admin.server.PageTaskEdit; +import com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceDto; +import com.evolveum.midpoint.web.session.UserProfileStorage; +import com.evolveum.midpoint.web.util.OnePageParameterEncoder; +import com.evolveum.midpoint.wf.util.ApprovalUtils; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; +import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider; +import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; + +import java.util.ArrayList; +import java.util.List; + +import static com.evolveum.midpoint.web.page.admin.server.dto.OperationResultStatusIcon.FATAL_ERROR; +import static com.evolveum.midpoint.web.page.admin.server.dto.OperationResultStatusIcon.IN_PROGRESS; +import static com.evolveum.midpoint.web.page.admin.server.dto.OperationResultStatusIcon.SUCCESS; +import static com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceDto.*; + +/** + * @author Kate + * @author mederly + */ + +public class WorkflowRequestsPanel extends BasePanel { + + private static final String ID_REQUESTS_TABLE = "requestsTable"; + + private ISortableDataProvider provider; + + public WorkflowRequestsPanel(String id, ISortableDataProvider provider, + UserProfileStorage.TableId tableId, int pageSize) { + super(id); + this.provider = provider; + initLayout(tableId, pageSize); + } + + private void initLayout(UserProfileStorage.TableId tableId, int pageSize) { + BoxedTablePanel table = new BoxedTablePanel<>(ID_REQUESTS_TABLE, provider, initColumns(), tableId, pageSize); + table.setOutputMarkupId(true); + add(table); + } + + private List> initColumns() { + + List> columns = new ArrayList>(); + + IColumn column = new CheckBoxHeaderColumn<>(); + columns.add(column); + + columns.add(new PropertyColumn(createStringResource("pageProcessInstances.item.object"), F_OBJECT_NAME)); + columns.add(new PropertyColumn(createStringResource("pageProcessInstances.item.target"), F_TARGET_NAME)); + + if (WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_WORK_ITEMS_ALL_URL, + AuthorizationConstants.AUTZ_UI_WORK_ITEMS_PROCESS_INSTANCE_URL)) { + columns.add(new LinkColumn(createStringResource("MyRequestsPanel.name"), "name") { + @Override + public void onClick(AjaxRequestTarget target, IModel rowModel) { + ProcessInstanceDto piDto = rowModel.getObject(); + itemDetailsPerformed(target, piDto.getTaskOid()); + } + }); + } else { + columns.add(new PropertyColumn(createStringResource("MyRequestsPanel.name"), F_NAME)); + } + + columns.add(new PropertyColumn(createStringResource("pageProcessInstances.item.state"), F_STATE)); + + columns.add(new PropertyColumn(createStringResource("pageProcessInstances.item.started"), F_START_FORMATTED)); + + columns.add(new IconColumn(createStringResource("pageProcessInstances.item.result")) { + @Override + protected IModel createIconModel(final IModel rowModel) { + return new AbstractReadOnlyModel() { + @Override + public String getObject() { + return choose(rowModel, IN_PROGRESS.getIcon(), SUCCESS.getIcon(), FATAL_ERROR.getIcon()); + } + }; + } + + @Override + protected IModel createTitleModel(final IModel rowModel) { + return new AbstractReadOnlyModel() { + @Override + public String getObject() { + return choose(rowModel, + createStringResource("MyRequestsPanel.inProgress").getString(), + createStringResource("MyRequestsPanel.approved").getString(), + createStringResource("MyRequestsPanel.rejected").getString()); + } + }; + } + + private String choose(IModel rowModel, String inProgress, String approved, String rejected) { + ProcessInstanceDto dto = rowModel.getObject(); + Boolean result = ApprovalUtils.approvalBooleanValue(dto.getAnswer()); + if (result == null) { + return inProgress; + } else { + return result ? approved : rejected; + } + } + }); + + columns.add(new PropertyColumn(createStringResource("pageProcessInstances.item.finished"), F_END_FORMATTED)); + + return columns; + } + + + + private void itemDetailsPerformed(AjaxRequestTarget target, String pid) { + PageParameters parameters = new PageParameters(); + parameters.add(OnePageParameterEncoder.PARAMETER, pid); + setResponsePage(new PageTaskEdit(parameters, this.getPageBase())); + } +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/DecisionDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/DecisionDto.java index ba9d5a92b1b..0714461968b 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/DecisionDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/DecisionDto.java @@ -38,10 +38,8 @@ public class DecisionDto extends Selectable { private Date time; public DecisionDto(DecisionType decision) { - if (decision.getApprover() != null && decision.getApprover().getName() != null) { - this.user = decision.getApprover().getName().getOrig(); - } else if (decision.getApproverName() != null) { - this.user = decision.getApproverName(); + if (decision.getApproverRef() != null && decision.getApproverRef().getTargetName() != null) { + this.user = decision.getApproverRef().getTargetName().getOrig(); } else { this.user = decision.getApproverRef().getOid(); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceDto.java index baea68572d3..7fde8a57f8e 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceDto.java @@ -19,119 +19,124 @@ import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.web.component.util.Selectable; -import com.evolveum.midpoint.web.component.wf.processes.itemApproval.ItemApprovalPanel; import com.evolveum.midpoint.wf.util.ApprovalUtils; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessInstanceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; - +import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; import org.apache.commons.lang.Validate; +import org.apache.wicket.Component; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.model.AbstractReadOnlyModel; +import org.apache.wicket.model.IModel; + +import javax.xml.datatype.XMLGregorianCalendar; +import java.util.Date; -import java.util.ArrayList; -import java.util.List; +import static com.evolveum.midpoint.gui.api.util.WebComponentUtil.formatDate; +import static com.evolveum.midpoint.prism.xml.XmlTypeConverter.*; /** * @author mederly */ public class ProcessInstanceDto extends Selectable { - public static final String F_SHADOW_TASK = "shadowTask"; - public static final String F_SHADOW_TASK_EXISTING = "shadowTaskExisting"; - - WfProcessInstanceType processInstance; - ProcessInstanceState processInstanceState; - - private String shadowTaskName; - private boolean shadowTaskExisting; - - public ProcessInstanceDto(WfProcessInstanceType processInstance, Task shadowTask) { - Validate.notNull(processInstance); - this.processInstance = processInstance; - this.processInstanceState = (ProcessInstanceState) processInstance.getState(); - if (shadowTask != null) { - shadowTaskName = PolyString.getOrig(shadowTask.getName()); - shadowTaskExisting = true; - } else { - shadowTaskExisting = false; - } - } + public static final String F_OBJECT_NAME = "objectName"; + public static final String F_TARGET_NAME = "targetName"; + public static final String F_SHADOW_TASK = "shadowTask"; // DELETE THIS! + public static final String F_NAME = "name"; + public static final String F_START_FORMATTED = "startFormatted"; + public static final String F_END_FORMATTED = "endFormatted"; + public static final String F_STATE = "state"; + public static final String F_ANSWER = "answer"; - public String getStartedTime() { - return processInstance.getStartTimestamp() == null ? "-" : WebComponentUtil.formatDate(XmlTypeConverter.toDate(processInstance.getStartTimestamp())); - } + private TaskType task; - public String getFinishedTime() { - return processInstance.getEndTimestamp() == null ? "-" : WebComponentUtil.formatDate(XmlTypeConverter.toDate(processInstance.getEndTimestamp())); + public ProcessInstanceDto(TaskType task) { + Validate.notNull(task, "Task is null"); + Validate.notNull(task.getWorkflowContext(), "Task has no workflow context"); + this.task = task; } - public String getName() { - return PolyString.getOrig(processInstance.getName()); + public XMLGregorianCalendar getStartTimestamp() { + return task.getWorkflowContext().getStartTimestamp(); } - public String getInstanceId() { - return processInstance.getProcessInstanceId(); + public XMLGregorianCalendar getEndTimestamp() { + return task.getWorkflowContext().getEndTimestamp(); } - public WfProcessInstanceType getProcessInstance() { - return processInstance; + public String getStartFormatted() { + Date started = toDate(getStartTimestamp()); + return formatDate(started); } - public List getWorkItems() { - List retval = new ArrayList(); - if (processInstance.getWorkItems() != null) { - for (WorkItemType workItem : processInstance.getWorkItems()) { - retval.add(new WorkItemDto(workItem)); - } - } - return retval; + public String getEndFormatted() { + return formatDate(toDate(getEndTimestamp())); } - public String getAnswer() { - if (processInstanceState == null) { - return null; - } - return processInstanceState.getAnswer(); + public String getName() { + return PolyString.getOrig(task.getName()); } - public boolean isAnswered() { - return getAnswer() != null; - } + public String getAnswer() { + return task.getWorkflowContext().getAnswer(); + } + + public String getObjectName() { + return WebComponentUtil.getName(task.getWorkflowContext().getObjectRef()); + } + + public String getTargetName() { + return WebComponentUtil.getName(task.getWorkflowContext().getTargetRef()); + } + + public String getState() { + return task.getWorkflowContext().getState(); + } + +// public List getWorkItems() { +// List retval = new ArrayList(); +// if (processInstance.getWorkItems() != null) { +// for (WorkItemType workItem : processInstance.getWorkItems()) { +// retval.add(new WorkItemDto(workItem)); +// } +// } +// return retval; +// } + +// public String getAnswer() { +// if (processInstanceState == null) { +// return null; +// } +// return processInstanceState.getAnswer(); +// } + +// public boolean isAnswered() { +// return getAnswer() != null; +// } // null if not answered or answer is not true/false - public Boolean getAnswerAsBoolean() { - return ApprovalUtils.approvalBooleanValue(getAnswer()); - } +// public Boolean getAnswerAsBoolean() { +// return ApprovalUtils.approvalBooleanValue(getAnswer()); +// } - public boolean isFinished() { - return processInstance.isFinished(); - } +// public boolean isFinished() { +// return processInstance.isFinished(); +// } - public boolean isShadowTaskExisting() { - return shadowTaskExisting; - } +// public ProcessInstanceState getInstanceState() { +// return (ProcessInstanceState) processInstance.getState(); +// } - public String getShadowTask() { - String oid = processInstanceState.getShadowTaskOid(); - if (shadowTaskName != null) { - return shadowTaskName + " (" + oid + ")"; - } else { - return oid; - } - } - - public ProcessInstanceState getInstanceState() { - return (ProcessInstanceState) processInstance.getState(); - } +// public String getShadowTaskOid() { +// return processInstanceState.getShadowTaskOid(); +// } - public String getShadowTaskOid() { - return processInstanceState.getShadowTaskOid(); + public void reviveIfNeeded(Component component) { +// WebComponentUtil.reviveIfNeeded(processInstance, component); +// WebComponentUtil.reviveIfNeeded(processInstanceState, component); } - public void reviveIfNeeded(ItemApprovalPanel component) { - WebComponentUtil.reviveIfNeeded(processInstance, component); - WebComponentUtil.reviveIfNeeded(processInstanceState, component); + public String getTaskOid() { + return task.getOid(); } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceDtoProvider.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceDtoProvider.java index c0b6680d697..567d4a8d950 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceDtoProvider.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceDtoProvider.java @@ -16,23 +16,36 @@ package com.evolveum.midpoint.web.page.admin.workflow.dto; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; -import com.evolveum.midpoint.model.api.WorkflowService; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.query.ObjectPaging; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.builder.QueryBuilder; +import com.evolveum.midpoint.prism.query.builder.S_FilterEntry; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.MidPointPrincipal; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.data.BaseSortableDataProvider; import com.evolveum.midpoint.web.security.SecurityUtils; -import com.evolveum.midpoint.wf.api.WorkflowManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessInstanceType; - +import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; import org.apache.wicket.Component; +import java.util.Collection; import java.util.Iterator; import java.util.List; +import static com.evolveum.midpoint.gui.api.util.WebComponentUtil.safeLongToInteger; +import static com.evolveum.midpoint.schema.GetOperationOptions.*; +import static com.evolveum.midpoint.schema.SelectorOptions.createCollection; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_OBJECT_REF; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_WORKFLOW_CONTEXT; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType.*; + /** * @author lazyman * @author mederly @@ -50,8 +63,7 @@ public class ProcessInstanceDtoProvider extends BaseSortableDataProvider internalIterator(long first, long return getAvailableData().iterator(); } + private ObjectQuery getObjectQuery() throws SchemaException { + String currentUserOid = currentUser(); + S_FilterEntry q = QueryBuilder.queryFor(TaskType.class, getPrismContext()); + if (requestedBy) { + q = q.item(F_WORKFLOW_CONTEXT, F_REQUESTER_REF).ref(currentUserOid).and(); + } + if (requestedFor) { + q = q.item(F_OBJECT_REF).ref(currentUserOid).and(); + } + return q + .not().item(F_WORKFLOW_CONTEXT, F_PROCESS_INSTANCE_ID).isNull() + .desc(F_WORKFLOW_CONTEXT, F_START_TIMESTAMP) + .build(); + } + @Override protected int internalSize() { int count = 0; - OperationResult result = new OperationResult(OPERATION_COUNT_ITEMS); + Task opTask = getTaskManager().createTaskInstance(OPERATION_COUNT_ITEMS); + OperationResult result = opTask.getResult(); try { - WorkflowService workflowService = getWorkflowService(); - count = workflowService.countProcessInstancesRelatedToUser(currentUser(), requestedBy, requestedFor, finished, result); + ObjectQuery query = getObjectQuery(); + count = getModel().countObjects(TaskType.class, query, null, opTask, result); } catch (Exception ex) { - String msg = "Couldn't list process instances"; - LoggingUtils.logException(LOGGER, msg, ex); + String msg = "Couldn't count process instances"; + LoggingUtils.logUnexpectedException(LOGGER, msg, ex); result.recordFatalError(msg, ex); } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceNewDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceNewDto.java new file mode 100644 index 00000000000..937aaa2e10f --- /dev/null +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/ProcessInstanceNewDto.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2010-2013 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.web.page.admin.workflow.dto; + +import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.web.component.util.Selectable; +import com.evolveum.midpoint.wf.util.ApprovalUtils; +import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType; +import org.apache.commons.lang.Validate; + +/** + * @author mederly + */ +public class ProcessInstanceNewDto extends Selectable { + + public static final String F_SHADOW_TASK = "shadowTask"; + public static final String F_SHADOW_TASK_EXISTING = "shadowTaskExisting"; + + + private WfContextType workflowContext; + + public ProcessInstanceNewDto(TaskType task) { + Validate.notNull(task); + Validate.notNull(task.getWorkflowContext()); + this.workflowContext = task.getWorkflowContext(); + } + + public String getStartedTime() { + return workflowContext.getStartTimestamp() == null ? "-" : WebComponentUtil.formatDate(XmlTypeConverter.toDate(workflowContext.getStartTimestamp())); + } + + public String getFinishedTime() { + return workflowContext.getEndTimestamp() == null ? "-" : WebComponentUtil.formatDate(XmlTypeConverter.toDate(workflowContext.getEndTimestamp())); + } + + public String getName() { + return workflowContext.getProcessInstanceName(); + } + + public String getInstanceId() { + return workflowContext.getProcessInstanceId(); + } + +// public List getWorkItems() { +// List retval = new ArrayList(); +// if (processInstance.getWorkItems() != null) { +// for (WorkItemType workItem : processInstance.getWorkItems()) { +// retval.add(new WorkItemDto(workItem)); +// } +// } +// return retval; +// } + + public String getAnswer() { + return workflowContext.getAnswer(); + } + + public boolean isAnswered() { + return getAnswer() != null; + } + + // null if not answered or answer is not true/false + public Boolean getAnswerAsBoolean() { + return ApprovalUtils.approvalBooleanValue(getAnswer()); + } + + public boolean isFinished() { + return workflowContext.getEndTimestamp() != null; + } + +} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDetailedDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDetailedDto.java deleted file mode 100644 index 9f5ffe5d268..00000000000 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDetailedDto.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.web.page.admin.workflow.dto; - -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.delta.ChangeType; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.polystring.PolyString; -import com.evolveum.midpoint.schema.DeltaConvertor; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.web.component.model.delta.ContainerValueDto; -import com.evolveum.midpoint.web.component.model.delta.DeltaDto; -import com.evolveum.midpoint.web.component.util.Selectable; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.GeneralChangeApprovalWorkItemContents; - -/** - * @author lazyman - */ -public class WorkItemDetailedDto extends WorkItemDto { - - public static final String F_DELTA = "delta"; - public static final String F_REQUESTER = "requester"; - public static final String F_OBJECT_OLD = "objectOld"; - public static final String F_OBJECT_NEW = "objectNew"; - public static final String F_RELATED_OBJECT = "relatedObject"; - - DeltaDto deltaDto; - - public WorkItemDetailedDto(WorkItemType workItem, PrismContext prismContext) throws SchemaException { - super(workItem); - if (workItem.getContents() instanceof GeneralChangeApprovalWorkItemContents) { - GeneralChangeApprovalWorkItemContents wic = (GeneralChangeApprovalWorkItemContents) workItem.getContents(); - if (wic.getObjectDelta() != null) { - deltaDto = new DeltaDto(DeltaConvertor.createObjectDelta(wic.getObjectDelta(), prismContext)); - } - } - if (deltaDto == null) { // TODO!!!! - deltaDto = new DeltaDto(ObjectDelta.createEmptyDelta(ObjectType.class, "dummy", prismContext, ChangeType.MODIFY)); - } - } - - public String getName() { - return PolyString.getOrig(workItem.getName()); - } - - public String getOwner() { - return workItem.getAssigneeRef() != null ? workItem.getAssigneeRef().getOid() : null; - } - - public WorkItemType getWorkItem() { - return workItem; - } - - public DeltaDto getDelta() { - return deltaDto; - } - - public ContainerValueDto getRequester() { - if (workItem.getRequester() != null) { - return new ContainerValueDto(workItem.getRequester().asPrismObject()); - } else { - return null; - } - } - - private GeneralChangeApprovalWorkItemContents getWic() { - if (workItem.getContents() instanceof GeneralChangeApprovalWorkItemContents) { - return (GeneralChangeApprovalWorkItemContents) workItem.getContents(); - } else { - return null; - } - } - - public ContainerValueDto getObjectOld() { - if (getWic() != null && getWic().getObjectOld() != null) { - return new ContainerValueDto(getWic().getObjectOld().asPrismObject()); - } else { - return null; - } - } - - public ContainerValueDto getObjectNew() { - if (getWic() != null && getWic().getObjectNew() != null) { - return new ContainerValueDto(getWic().getObjectNew().asPrismObject()); - } else { - return null; - } - } - - public ContainerValueDto getRelatedObject() { - if (getWic() != null && getWic().getRelatedObject() != null) { - return new ContainerValueDto(getWic().getRelatedObject().asPrismObject()); - } else { - return null; - } - } -} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDto.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDto.java index 784506f319f..0b34df37a09 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDto.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDto.java @@ -17,59 +17,86 @@ package com.evolveum.midpoint.web.page.admin.workflow.dto; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; +import com.evolveum.midpoint.model.api.ModelInteractionService; +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.web.component.prism.show.SceneDto; +import com.evolveum.midpoint.web.component.prism.show.SceneUtil; import com.evolveum.midpoint.web.component.util.Selectable; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; - -import org.apache.commons.lang.StringUtils; - -import java.util.List; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; /** * @author lazyman + * @author mederly */ public class WorkItemDto extends Selectable { public static final String F_NAME = "name"; - public static final String F_OWNER_OR_CANDIDATES = "ownerOrCandidates"; - public static final String F_CANDIDATES = "candidates"; - public static final String F_ASSIGNEE = "assignee"; public static final String F_CREATED = "created"; + public static final String F_PROCESS_STARTED = "processStarted"; + public static final String F_ASSIGNEE_OR_CANDIDATES = "assigneeOrCandidates"; + public static final String F_ASSIGNEE = "assignee"; + public static final String F_CANDIDATES = "candidates"; + + public static final String F_OBJECT_NAME = "objectName"; + public static final String F_TARGET_NAME = "targetName"; + public static final String F_REQUESTER_NAME = "requesterName"; + public static final String F_REQUESTER_FULL_NAME = "requesterFullName"; + public static final String F_APPROVER_COMMENT = "approverComment"; - WorkItemType workItem; + public static final String F_WORKFLOW_CONTEXT = "workflowContext"; // use with care + public static final String F_DELTAS = "deltas"; + + // workItem may or may not contain resolved taskRef; + // and this task may or may not contain filled-in workflowContext -> and then requesterRef object + // + // Depending on expected use (work item list vs. work item details) + + protected WorkItemType workItem; + protected SceneDto deltas; + protected String approverComment; public WorkItemDto(WorkItemType workItem) { this.workItem = workItem; } - public String getName() { - return PolyString.getOrig(workItem.getName()); + public void prepareDeltaVisualization(String sceneNameKey, PrismContext prismContext, + ModelInteractionService modelInteractionService, Task opTask, OperationResult result) throws SchemaException { + TaskType task = WebComponentUtil.getObjectFromReference(workItem.getTaskRef(), TaskType.class); + if (task == null || task.getWorkflowContext() == null) { + return; + } + if (!(task.getWorkflowContext().getProcessorSpecificState() instanceof WfPrimaryChangeProcessorStateType)) { + return; + } + WfPrimaryChangeProcessorStateType state = (WfPrimaryChangeProcessorStateType) task.getWorkflowContext().getProcessorSpecificState(); + Scene deltasScene = SceneUtil.visualizeObjectTreeDeltas(state.getDeltasToProcess(), sceneNameKey, prismContext, modelInteractionService, opTask, result); + deltas = new SceneDto(deltasScene); + } + + public String getWorkItemId() { + return workItem.getWorkItemId(); } - public String getOwner() { - return workItem.getAssigneeRef() != null ? workItem.getAssigneeRef().getOid() : null; + public String getName() { + return workItem.getName(); } - public WorkItemType getWorkItem() { - return workItem; + public String getCreated() { + return WebComponentUtil.formatDate(XmlTypeConverter.toDate(workItem.getWorkItemCreatedTimestamp())); } - public String getCreated() { - if (workItem.getMetadata() != null && workItem.getMetadata().getCreateTimestamp() != null) { - return WebComponentUtil.formatDate(XmlTypeConverter.toDate(workItem.getMetadata().getCreateTimestamp())); - } else { - return null; - } + public String getProcessStarted() { + return WebComponentUtil.formatDate(XmlTypeConverter.toDate(workItem.getProcessStartedTimestamp())); } - public String getOwnerOrCandidates() { + public String getAssigneeOrCandidates() { String assignee = getAssignee(); if (assignee != null) { return assignee; @@ -79,61 +106,85 @@ public String getOwnerOrCandidates() { } public String getAssignee() { - if (workItem.getAssignee() != null) { - if (workItem.getAssignee().getName() != null) { - return workItem.getAssignee().getName().getOrig(); - } else { - return workItem.getAssignee().getOid(); - } - } else if (workItem.getAssigneeRef() != null) { - return workItem.getAssigneeRef().getOid(); - } else { - return null; - } + return WebComponentUtil.getName(workItem.getAssigneeRef()); } - // what an ugly method :| TODO rework some day [also add users] public String getCandidates() { - StringBuilder retval = new StringBuilder(); + StringBuilder sb = new StringBuilder(); boolean first = true; - boolean referenceOnly = false; - // we assume that either all roles have full reference information, or none of them - for (AbstractRoleType roleType : workItem.getCandidateRoles()) { + for (ObjectReferenceType roleRef : workItem.getCandidateRolesRef()) { if (!first) { - retval.append(", "); + sb.append(", "); } else { first = false; } - if (roleType.getOid() == null) { // no object information, only reference is present - referenceOnly = true; - break; - } - retval.append(PolyString.getOrig(roleType.getName())); - if (roleType instanceof RoleType) { - retval.append(" (role)"); - } else if (roleType instanceof OrgType) { - retval.append(" (org)"); + sb.append(WebComponentUtil.getName(roleRef)); + if (RoleType.COMPLEX_TYPE.equals(roleRef.getType())) { + sb.append(" (role)"); + } else if (OrgType.COMPLEX_TYPE.equals(roleRef.getType())) { + sb.append(" (org)"); } } - if (referenceOnly) { - // start again - retval = new StringBuilder(); - first = true; - for (ObjectReferenceType roleRef : workItem.getCandidateRolesRef()) { - if (!first) { - retval.append(", "); - } else { - first = false; - } - retval.append(roleRef.getOid()); - if (RoleType.COMPLEX_TYPE.equals(roleRef.getType())) { - retval.append(" (role)"); - } else if (OrgType.COMPLEX_TYPE.equals(roleRef.getType())) { - retval.append(" (org)"); - } + for (ObjectReferenceType userRef : workItem.getCandidateUsersRef()) { + if (!first) { + sb.append(", "); + } else { + first = false; } + sb.append(WebComponentUtil.getName(userRef)); + sb.append(" (user)"); } - return retval.toString(); + return sb.toString(); + } + + public String getObjectName() { + return WebComponentUtil.getName(workItem.getObjectRef()); + } + + public String getTargetName() { + return WebComponentUtil.getName(workItem.getTargetRef()); + } + + public WfContextType getWorkflowContext() { + TaskType task = WebComponentUtil.getObjectFromReference(workItem.getTaskRef(), TaskType.class); + if (task == null || task.getWorkflowContext() == null) { + return null; + } else { + return task.getWorkflowContext(); + } + } + + public String getRequesterName() { + WfContextType workflowContext = getWorkflowContext(); + return workflowContext != null ? WebComponentUtil.getName(workflowContext.getRequesterRef()) : null; + } + + public String getRequesterFullName() { + UserType requester = getRequester(); + return requester != null ? PolyString.getOrig(requester.getFullName()) : null; + } + + public UserType getRequester() { + WfContextType wfContext = getWorkflowContext(); + if (wfContext == null) { + return null; + } + return WebComponentUtil.getObjectFromReference(wfContext.getRequesterRef(), UserType.class); + } + + public String getApproverComment() { + return approverComment; + } + + public void setApproverComment(String approverComment) { + this.approverComment = approverComment; + } + + public WorkItemType getWorkItem() { + return workItem; } + public SceneDto getDeltas() { + return deltas; + } } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDtoProvider.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDtoProvider.java index 83c6852f9c4..7c162e4eb80 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDtoProvider.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/workflow/dto/WorkItemDtoProvider.java @@ -16,26 +16,30 @@ package com.evolveum.midpoint.web.page.admin.workflow.dto; -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; -import com.evolveum.midpoint.model.api.WorkflowService; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectPaging; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.builder.QueryBuilder; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.MidPointPrincipal; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.data.BaseSortableDataProvider; import com.evolveum.midpoint.web.security.SecurityUtils; -import com.evolveum.midpoint.wf.api.WorkflowManager; -import com.evolveum.midpoint.wf.api.WorkflowException; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; - +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.wicket.Component; -import java.util.Iterator; -import java.util.List; +import java.util.*; + +import static com.evolveum.midpoint.gui.api.util.WebComponentUtil.*; +import static com.evolveum.midpoint.prism.query.OrderDirection.DESCENDING; +import static com.evolveum.midpoint.schema.GetOperationOptions.createResolve; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType.*; /** * @author lazyman @@ -49,7 +53,7 @@ public class WorkItemDtoProvider extends BaseSortableDataProvider { boolean assigned; - public static String currentUser() { + public String currentUser() { MidPointPrincipal principal = SecurityUtils.getPrincipalUser(); if (principal == null) { return "Unknown"; @@ -67,32 +71,27 @@ public WorkItemDtoProvider(Component component, boolean assigned) { public Iterator internalIterator(long first, long count) { getAvailableData().clear(); + Task task = getTaskManager().createTaskInstance(); OperationResult result = new OperationResult(OPERATION_LIST_ITEMS); try { -// SortParam sortParam = getSort(); -// OrderDirectionType order; -// if (sortParam.isAscending()) { -// order = OrderDirectionType.ASCENDING; -// } else { -// order = OrderDirectionType.DESCENDING; -// } - - WorkflowService wfm = getWorkflowService(); - List items = wfm.listWorkItemsRelatedToUser(currentUser(), assigned, - WebComponentUtil.safeLongToInteger(first), WebComponentUtil.safeLongToInteger(count), result); + ObjectQuery query = createQuery(first, count); + Collection> options = + Arrays.asList( + SelectorOptions.create(new ItemPath(F_ASSIGNEE_REF), createResolve())); + List items = getModel().searchContainers(WorkItemType.class, query, options, task, result); for (WorkItemType item : items) { try { getAvailableData().add(new WorkItemDto(item)); } catch (Exception e) { - LoggingUtils.logException(LOGGER, "Unhandled exception when listing work item {}", e, item); + LoggingUtils.logUnexpectedException(LOGGER, "Unhandled exception when listing work item {}", e, item); result.recordFatalError("Couldn't list work item.", e); } } - } catch (Exception ex) { - LoggingUtils.logException(LOGGER, "Unhandled exception when listing work items", ex); + } catch (SchemaException|ObjectNotFoundException|SecurityViolationException|ConfigurationException|RuntimeException ex) { + LoggingUtils.logUnexpectedException(LOGGER, "Unhandled exception when listing work items", ex); result.recordFatalError("Couldn't list work items.", ex); } @@ -103,14 +102,31 @@ public Iterator internalIterator(long first, long count) return getAvailableData().iterator(); } + private ObjectQuery createQuery(long first, long count) throws SchemaException { + ObjectQuery query = createQuery(); + query.setPaging(ObjectPaging.createPaging(safeLongToInteger(first), safeLongToInteger(count), F_WORK_ITEM_CREATED_TIMESTAMP, DESCENDING)); + return query; + } + + private ObjectQuery createQuery() throws SchemaException { + if (assigned) { + return QueryBuilder.queryFor(WorkItemType.class, getPrismContext()) + .item(WorkItemType.F_ASSIGNEE_REF).ref(currentUser()) + .build(); + } else { + throw new UnsupportedOperationException("search by more than one ref is not supported"); + } + } + @Override protected int internalSize() { int count = 0; + Task task = getTaskManager().createTaskInstance(); OperationResult result = new OperationResult(OPERATION_COUNT_ITEMS); - WorkflowService workflowService = getWorkflowService(); try { - count = workflowService.countWorkItemsRelatedToUser(currentUser(), assigned, result); - } catch (SchemaException|ObjectNotFoundException e) { + ObjectQuery query = createQuery(); + count = getModel().countContainers(WorkItemType.class, query, null, task, result); + } catch (SchemaException|RuntimeException e) { throw new SystemException("Couldn't count work items: " + e.getMessage(), e); } @@ -124,4 +140,32 @@ protected int internalSize() { return count; } + + // TODO - fix this temporary implementation (perhaps by storing 'groups' in user context on logon) + public List getGroupsForUser(String oid, OperationResult result) throws SchemaException, ObjectNotFoundException { + List retval = new ArrayList<>(); + UserType userType = getRepositoryService().getObject(UserType.class, oid, null, result).asObjectable(); + for (AssignmentType assignmentType : userType.getAssignment()) { + ObjectReferenceType ref = assignmentType.getTargetRef(); + if (ref != null) { + String groupName = objectReferenceToGroupName(ref); + if (groupName != null) { // if the reference represents a group name (i.e. it is not e.g. an account ref) + retval.add(groupName); + } + } + } + return retval; + } + + private String objectReferenceToGroupName(ObjectReferenceType ref) { + if (RoleType.COMPLEX_TYPE.equals(ref.getType())) { + return "role:" + ref.getOid(); + } else if (OrgType.COMPLEX_TYPE.equals(ref.getType())) { + return "org:" + ref.getOid(); + } else { + return null; + } + } + + } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageSelfDashboard.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageSelfDashboard.java index 2c54751d621..bb5bf0e283c 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageSelfDashboard.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/PageSelfDashboard.java @@ -18,13 +18,14 @@ import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; +import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.prism.query.builder.QueryBuilder; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.application.AuthorizationAction; @@ -32,21 +33,25 @@ import com.evolveum.midpoint.web.component.SecurityContextAwareCallable; import com.evolveum.midpoint.web.component.breadcrumbs.Breadcrumb; import com.evolveum.midpoint.web.component.util.CallableResult; +import com.evolveum.midpoint.web.component.util.ListDataProvider; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; -import com.evolveum.midpoint.web.component.wf.WorkItemsPanel; +import com.evolveum.midpoint.web.component.wf.WorkItemsTablePanel; import com.evolveum.midpoint.web.page.admin.home.component.AsyncDashboardPanel; import com.evolveum.midpoint.web.page.admin.home.component.DashboardColor; import com.evolveum.midpoint.web.page.admin.home.dto.AccountCallableResult; +import com.evolveum.midpoint.web.page.admin.workflow.WorkflowRequestsPanel; import com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceDto; import com.evolveum.midpoint.web.page.admin.workflow.dto.WorkItemDto; -import com.evolveum.midpoint.web.page.self.component.LinksPanel; import com.evolveum.midpoint.web.page.self.component.DashboardSearchPanel; -import com.evolveum.midpoint.web.page.self.component.MyRequestsPanel; +import com.evolveum.midpoint.web.page.self.component.LinksPanel; import com.evolveum.midpoint.web.security.SecurityUtils; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; +import com.evolveum.midpoint.xml.ns._public.common.common_3.RichHyperlinkType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import org.apache.commons.lang.Validate; import org.apache.wicket.Component; +import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; @@ -55,6 +60,10 @@ import java.util.ArrayList; import java.util.List; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_WORKFLOW_CONTEXT; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType.*; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType.F_WORK_ITEM_CREATED_TIMESTAMP; + /** * @author Viliam Repan (lazyman) * @author Kate Honchar @@ -122,7 +131,9 @@ public void detach() { }); add(linksPanel); - AsyncDashboardPanel> workItemsPanel = + final PrismContext prismContext = getPrismContext(); + + AsyncDashboardPanel> workItemsPanel = new AsyncDashboardPanel>(ID_WORK_ITEMS_PANEL, createStringResource("PageSelfDashboard.workItems"), "fa fa-fw fa-tasks", DashboardColor.RED) { @@ -135,14 +146,15 @@ protected SecurityContextAwareCallable>> create @Override public CallableResult> callWithContextPrepared() throws Exception { - return loadWorkItems(); + return loadWorkItems(prismContext); } }; } @Override protected Component getMainComponent(String markupId) { - return new WorkItemsPanel(markupId, new PropertyModel>(getModel(), CallableResult.F_VALUE), false); + ISortableDataProvider provider = new ListDataProvider(this, new PropertyModel>(getModel(), CallableResult.F_VALUE)); + return new WorkItemsTablePanel(markupId, provider, null, 10, false); } }; @@ -167,14 +179,15 @@ protected SecurityContextAwareCallable>> @Override public CallableResult> callWithContextPrepared() throws Exception { - return loadMyRequests(); + return loadMyRequests(prismContext); } }; } @Override protected Component getMainComponent(String markupId) { - return new MyRequestsPanel(markupId, new PropertyModel>(getModel(), CallableResult.F_VALUE)); + ISortableDataProvider provider = new ListDataProvider(this, new PropertyModel>(getModel(), CallableResult.F_VALUE)); + return new WorkflowRequestsPanel(markupId, provider, null, 10); } }; @@ -188,12 +201,12 @@ public boolean isVisible() { } - private CallableResult> loadWorkItems() { + private CallableResult> loadWorkItems(PrismContext prismContext) { LOGGER.debug("Loading work items."); AccountCallableResult callableResult = new AccountCallableResult(); - List list = new ArrayList(); + List list = new ArrayList<>(); callableResult.setValue(list); if (!getWorkflowManager().isEnabled()) { @@ -205,12 +218,16 @@ private CallableResult> loadWorkItems() { return callableResult; } - OperationResult result = new OperationResult(OPERATION_LOAD_WORK_ITEMS); + Task task = createSimpleTask(OPERATION_LOAD_WORK_ITEMS); + OperationResult result = task.getResult(); callableResult.setResult(result); try { - List workItems = getWorkflowService().listWorkItemsRelatedToUser(user.getOid(), - true, 0, MAX_WORK_ITEMS, result); + ObjectQuery query = QueryBuilder.queryFor(WorkItemType.class, prismContext) + .item(WorkItemType.F_ASSIGNEE_REF).ref(user.getOid()) + .desc(F_WORK_ITEM_CREATED_TIMESTAMP) + .build(); + List workItems = getModelService().searchContainers(WorkItemType.class, query, null, task, result); for (WorkItemType workItem : workItems) { list.add(new WorkItemDto(workItem)); } @@ -226,7 +243,7 @@ private CallableResult> loadWorkItems() { return callableResult; } - private CallableResult> loadMyRequests() { + private CallableResult> loadMyRequests(PrismContext prismContext) { LOGGER.debug("Loading requests."); @@ -243,31 +260,20 @@ private CallableResult> loadMyRequests() { return callableResult; } - OperationResult result = new OperationResult(OPERATION_LOAD_REQUESTS); + Task opTask = createSimpleTask(OPERATION_LOAD_REQUESTS); + OperationResult result = opTask.getResult(); callableResult.setResult(result); try { - List processInstanceTypes = getWorkflowService().listProcessInstancesRelatedToUser(user.getOid(), - true, false, false, 0, MAX_REQUESTS, result); - List processInstanceTypesFinished = getWorkflowService().listProcessInstancesRelatedToUser(user.getOid(), - true, false, true, 0, MAX_REQUESTS, result); - if (processInstanceTypes != null && processInstanceTypesFinished != null){ - processInstanceTypes.addAll(processInstanceTypesFinished); - } - for (WfProcessInstanceType processInstanceType : processInstanceTypes) { - ProcessInstanceState processInstanceState = (ProcessInstanceState) processInstanceType.getState(); - Task shadowTask = null; - if (processInstanceState != null) { - String shadowTaskOid = processInstanceState.getShadowTaskOid(); - try { - shadowTask = getTaskManager().getTask(shadowTaskOid, result); - } catch (ObjectNotFoundException e) { - // task is already deleted, no problem here - result.muteLastSubresultError(); - } - } - - list.add(new ProcessInstanceDto(processInstanceType, shadowTask)); + ObjectQuery query = QueryBuilder.queryFor(TaskType.class, prismContext) + .item(F_WORKFLOW_CONTEXT, F_REQUESTER_REF).ref(user.getOid()) + .and().not().item(F_WORKFLOW_CONTEXT, F_PROCESS_INSTANCE_ID).isNull() + .desc(F_WORKFLOW_CONTEXT, F_START_TIMESTAMP) + .build(); + + List> tasks = getModelService().searchObjects(TaskType.class, query, null, opTask, result); + for (PrismObject task : tasks) { + list.add(new ProcessInstanceDto(task.asObjectable())); } } catch (Exception e) { result.recordFatalError("Couldn't get list of work items.", e); @@ -281,6 +287,7 @@ private CallableResult> loadMyRequests() { return callableResult; } + private PrismObject loadUser() { MidPointPrincipal principal = SecurityUtils.getPrincipalUser(); Validate.notNull(principal, "No principal"); diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/component/MyRequestsPanel.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/component/MyRequestsPanel.java deleted file mode 100644 index b3634c6a6c8..00000000000 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/self/component/MyRequestsPanel.java +++ /dev/null @@ -1,181 +0,0 @@ -package com.evolveum.midpoint.web.page.self.component; - -import com.evolveum.midpoint.gui.api.util.WebComponentUtil; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.schema.result.OperationResultStatus; -import com.evolveum.midpoint.security.api.AuthorizationConstants; -import com.evolveum.midpoint.web.component.data.TablePanel; -import com.evolveum.midpoint.web.component.data.column.IconColumn; -import com.evolveum.midpoint.web.component.data.column.LinkColumn; -import com.evolveum.midpoint.web.component.util.ListDataProvider; -import com.evolveum.midpoint.web.component.util.SimplePanel; -import com.evolveum.midpoint.web.page.admin.resources.dto.ResourceController; -import com.evolveum.midpoint.web.page.admin.resources.dto.ResourceDto; -import com.evolveum.midpoint.web.page.admin.resources.dto.ResourceState; -import com.evolveum.midpoint.web.page.admin.server.dto.OperationResultStatusIcon; -import com.evolveum.midpoint.web.page.admin.workflow.PageProcessInstance; -import com.evolveum.midpoint.web.page.admin.workflow.dto.ProcessInstanceDto; -import com.evolveum.midpoint.web.util.OnePageParameterEncoder; -import com.evolveum.midpoint.wf.util.ApprovalUtils; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultStatusType; -import org.apache.commons.lang.time.DurationFormatUtils; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; -import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; -import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; -import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.model.AbstractReadOnlyModel; -import org.apache.wicket.model.IModel; -import org.apache.wicket.request.mapper.parameter.PageParameters; - -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -/** - * Created by Kate on 03.10.2015. - */ -public class MyRequestsPanel extends SimplePanel> { - private static final String ID_REQUESTS_TABLE = "requestsTable"; - - public MyRequestsPanel(String id) { - super(id, null); - } - - public MyRequestsPanel(String id, IModel> model) { - super(id, model); - } - - @Override - protected void initLayout() { - List> columns = new ArrayList>(); - if (WebComponentUtil.isAuthorized(AuthorizationConstants.AUTZ_UI_WORK_ITEMS_ALL_URL, - AuthorizationConstants.AUTZ_UI_WORK_ITEMS_PROCESS_INSTANCE_URL)) { - columns.add(new LinkColumn(createStringResource("MyRequestsPanel.name"), "name") { - - @Override - public void onClick(AjaxRequestTarget target, IModel rowModel) { - ProcessInstanceDto piDto = rowModel.getObject(); - itemDetailsPerformed(target, false, piDto.getProcessInstance().getProcessInstanceId()); - } - }); - } else { - columns.add(new AbstractColumn(createStringResource("MyRequestsPanel.name")) { - @Override - public void populateItem(Item> item, String componentId, - final IModel rowModel) { - item.add(new Label(componentId, new AbstractReadOnlyModel() { - - @Override - public Object getObject() { - ProcessInstanceDto pi = rowModel.getObject(); - return pi.getName(); - } - })); - } - }); - } - columns.add(new IconColumn(createStringResource("pageProcessInstances.item.result")) { - - @Override - protected IModel createIconModel(final IModel rowModel) { - return new AbstractReadOnlyModel() { - - @Override - public String getObject() { - ProcessInstanceDto dto = rowModel.getObject(); - Boolean result = ApprovalUtils.approvalBooleanValue(dto.getAnswer()); - if (result == null) { - return OperationResultStatusIcon - .parseOperationalResultStatus(OperationResultStatusType.IN_PROGRESS).getIcon(); - } else { - return result ? - OperationResultStatusIcon - .parseOperationalResultStatus(OperationResultStatusType.SUCCESS).getIcon() - : OperationResultStatusIcon - .parseOperationalResultStatus(OperationResultStatusType.FATAL_ERROR).getIcon(); - } - } - }; - } - - @Override - protected IModel createTitleModel(final IModel rowModel) { - return new AbstractReadOnlyModel() { - - @Override - public String getObject() { - ProcessInstanceDto dto = rowModel.getObject(); - Boolean result = ApprovalUtils.approvalBooleanValue(dto.getAnswer()); - if (result == null) { - return MyRequestsPanel.this.getString(OperationResultStatus.class.getSimpleName() + "." + - OperationResultStatus.IN_PROGRESS); - } else { - return result ? - createStringResource("MyRequestsPanel.approved").getString() - : createStringResource("MyRequestsPanel.rejected").getString(); - } - - } - }; - } - - }); - - columns.add(new AbstractColumn(createStringResource("MyRequestsPanel.started")) { - - @Override - public void populateItem(Item> item, String componentId, - final IModel rowModel) { - item.add(new Label(componentId, new AbstractReadOnlyModel() { - - @Override - public Object getObject() { - ProcessInstanceDto pi = rowModel.getObject(); - Date started = XmlTypeConverter.toDate(pi.getProcessInstance().getStartTimestamp()); - if (started == null) { - return "?"; - } else { - // todo i18n - return DurationFormatUtils.formatDurationWords(System.currentTimeMillis() - started.getTime(), true, true) + " ago"; - } - } - })); - } - }); - - columns.add(new AbstractColumn(createStringResource("pageProcessInstances.item.finished")) { - - @Override - public void populateItem(Item> item, String componentId, - final IModel rowModel) { - item.add(new Label(componentId, new AbstractReadOnlyModel() { - - @Override - public Object getObject() { - ProcessInstanceDto pi = rowModel.getObject(); - Date finished = XmlTypeConverter.toDate(pi.getProcessInstance().getEndTimestamp()); - if (finished == null) { - return getString("pageProcessInstances.notYet"); - } else { - return WebComponentUtil.formatDate(finished); - } - } - })); - } - }); - - ISortableDataProvider provider = new ListDataProvider(this, getModel()); - TablePanel accountsTable = new TablePanel(ID_REQUESTS_TABLE, provider, columns); - add(accountsTable); - } - - private void itemDetailsPerformed(AjaxRequestTarget target, boolean finished, String pid) { - PageParameters parameters = new PageParameters(); - parameters.add(OnePageParameterEncoder.PARAMETER, pid); - parameters.add(PageProcessInstance.PARAM_PROCESS_INSTANCE_FINISHED, finished); - setResponsePage(new PageProcessInstance(parameters, this.getPageBase())); - } -} diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java index 006781a494f..865214bf121 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/security/MidPointApplication.java @@ -33,6 +33,7 @@ import java.util.Properties; import java.util.Set; +import com.evolveum.midpoint.repo.api.RepositoryService; import org.apache.commons.configuration.Configuration; import org.apache.commons.io.IOUtils; import org.apache.velocity.runtime.resource.loader.StringResourceLoader; @@ -189,6 +190,8 @@ public class MidPointApplication extends AuthenticatedWebApplication { transient PrismContext prismContext; @Autowired transient TaskManager taskManager; + @Autowired + transient private RepositoryService repositoryService; // temporary @Autowired transient private WorkflowService workflowService; @Autowired @@ -413,6 +416,10 @@ public TaskManager getTaskManager() { return taskManager; } + public RepositoryService getRepositoryService() { + return repositoryService; + } + public TaskService getTaskService() { return taskService; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/ResourcesStorage.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/ResourcesStorage.java index d8342bd2b5b..6f70995e3ca 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/ResourcesStorage.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/ResourcesStorage.java @@ -16,39 +16,39 @@ package com.evolveum.midpoint.web.session; import com.evolveum.midpoint.prism.query.ObjectPaging; +import com.evolveum.midpoint.web.component.search.Search; import com.evolveum.midpoint.web.page.admin.resources.content.dto.AccountContentSearchDto; -import com.evolveum.midpoint.web.page.admin.resources.dto.ResourceSearchDto; /** - * @author shood - * */ -public class ResourcesStorage extends PageStorage{ + * @author shood + */ +public class ResourcesStorage extends PageStorage { /** - * DTO used for search purposes in {@link com.evolveum.midpoint.web.page.admin.resources.PageResources} - * */ - private ResourceSearchDto resourceSearch; + * DTO used for search purposes in {@link com.evolveum.midpoint.web.page.admin.resources.PageResources} + */ + private Search resourceSearch; /** - * Paging DTO used in table on page {@link com.evolveum.midpoint.web.page.admin.resources.PageResources} - * */ + * Paging DTO used in table on page {@link com.evolveum.midpoint.web.page.admin.resources.PageResources} + */ private ObjectPaging resourcePaging; /** - * DTO used for search in {@link com.evolveum.midpoint.web.page.admin.resources.content.PageContentAccounts} - * */ + * DTO used for search in {@link com.evolveum.midpoint.web.page.admin.resources.content.PageContentAccounts} + */ private AccountContentSearchDto accountContentSearch; /** - * Paging DTO used in table on page {@link com.evolveum.midpoint.web.page.admin.resources.content.PageContentAccounts} - * */ + * Paging DTO used in table on page {@link com.evolveum.midpoint.web.page.admin.resources.content.PageContentAccounts} + */ private ObjectPaging accountContentPaging; - public ResourceSearchDto getResourceSearch() { + public Search getResourceSearch() { return resourceSearch; } - public void setResourceSearch(ResourceSearchDto resourceSearch) { + public void setResourceSearch(Search resourceSearch) { this.resourceSearch = resourceSearch; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RolesStorage.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RolesStorage.java index 3fd91dc0e1d..95f58e5f761 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RolesStorage.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/RolesStorage.java @@ -16,28 +16,28 @@ package com.evolveum.midpoint.web.session; import com.evolveum.midpoint.prism.query.ObjectPaging; -import com.evolveum.midpoint.web.page.admin.roles.dto.RolesSearchDto; +import com.evolveum.midpoint.web.component.search.Search; /** - * @author shood - * */ -public class RolesStorage extends PageStorage{ + * @author shood + */ +public class RolesStorage extends PageStorage { /** - * DTO used for search in {@link com.evolveum.midpoint.web.page.admin.roles.PageRoles} - * */ - private RolesSearchDto rolesSearch; + * DTO used for search in {@link com.evolveum.midpoint.web.page.admin.roles.PageRoles} + */ + private Search rolesSearch; /** - * Paging DTO used in table on page {@link com.evolveum.midpoint.web.page.admin.roles.PageRoles} - * */ + * Paging DTO used in table on page {@link com.evolveum.midpoint.web.page.admin.roles.PageRoles} + */ private ObjectPaging rolesPaging; - public RolesSearchDto getRolesSearch() { + public Search getRolesSearch() { return rolesSearch; } - public void setRolesSearch(RolesSearchDto rolesSearch) { + public void setRolesSearch(Search rolesSearch) { this.rolesSearch = rolesSearch; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/UserProfileStorage.java b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/UserProfileStorage.java index ec37aa8ff28..f7832142c3c 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/UserProfileStorage.java +++ b/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/session/UserProfileStorage.java @@ -49,6 +49,7 @@ public enum TableId { PAGE_TASKS_NODES_PANEL, PAGE_USERS_PANEL, PAGE_WORK_ITEMS, + PAGE_WORKFLOW_REQUESTS, PAGE_RESOURCES_CONNECTOR_HOSTS, PAGE_REPORTS, PAGE_CERT_CAMPAIGN_OUTCOMES_PANEL, diff --git a/gui/admin-gui/src/main/resources/localization/Midpoint.properties b/gui/admin-gui/src/main/resources/localization/Midpoint.properties index cff952bd4c4..0f045c8c0c9 100644 --- a/gui/admin-gui/src/main/resources/localization/Midpoint.properties +++ b/gui/admin-gui/src/main/resources/localization/Midpoint.properties @@ -1207,6 +1207,7 @@ pageAdminFocus.task.category=Category pageAdminFocus.task.execution=Execution state pageAdminFocus.task.status=Status pageAdminFocus.button.save=Save +pageAdminFocus.button.previewChanges=Preview changes pageAdminFocus.button.abort=Abort pageAdminFocus.button.back=Back pageAdminFocus.title.confirmDelete=Confirm delete @@ -1716,6 +1717,9 @@ pageProcessInstances.item.name=Name pageProcessInstances.item.owner=Owner pageProcessInstances.item.result=Result pageProcessInstances.item.started=Started +pageProcessInstances.item.object=Object +pageProcessInstances.item.target=Target +pageProcessInstances.item.state=State pageProcessInstances.item.status=Status pageProcessInstances.message.noItemSelected=No process instance has been selected. pageProcessInstances.notYet=not yet @@ -2165,7 +2169,20 @@ pageWorkItem.requestedBy=Requested by\: pageWorkItem.requestedOn=Requested on\: pageWorkItem.requester.description=Requester pageWorkItem.requestSpecific.description=Your decision -pageWorkItem.requestSpecifics=Request specifics +workItemPanel.assignee=Assigned to\: +workItemPanel.candidates=Candidate assignees\: +workItemPanel.delta=Delta to be approved +workItemPanel.mainInfo=Basic information +workItemPanel.options=Options +workItemPanel.requestedBy=Requested by\: +workItemPanel.requestedOn=Requested on\: +workItemPanel.workItemCreatedOn=This work item created on\: +workItemPanel.requester.description=Requester +workItemPanel.subTitle=work item details +workItemPanel.title=Work to do\: +workItemPanel.changesToBeApproved=Changes to be approved +workItemPanel.approvalHistory=Approval history +workItemPanel.approverComment=Approver comment pageWorkItems.button.approve=Approve pageWorkItems.button.claim=Claim pageWorkItems.button.reject=Reject @@ -2185,7 +2202,9 @@ pageWorkItem.trackingData=Tracking data pageWorkItem.workItemCreatedOn=This work item created on\: passwordPanel.error=Passwords don't match. passwordPanel.passwordChange=Change +passwordPanel.passwordRemove=Remove passwordPanel.passwordSet=password is set +passwordPanel.passwordRemoveLabel=password will be removed past.ChangeType.ADD=Added past.ChangeType.DELETE=Deleted past.ChangeType.MODIFY=Modified @@ -2888,8 +2907,11 @@ WizardStep.title= WorkflowInformationPanel.label.history=Workflow process instance history WorkflowInformationPanel.link.processInstance=Workflow process instance is in state\: ${workflowLastDetails} WorkItemsPanel.assigned=Assigned to -WorkItemsPanel.created=Created +WorkItemsPanel.object=Object +WorkItemsPanel.target=Target WorkItemsPanel.name=Name +WorkItemsPanel.started=Process started +WorkItemsPanel.created=Created PageAdmin.menu.dashboard=Dashboard PageAdmin.menu.selfDashboard=Home PageAdmin.menu.selfService=SELF SERVICE @@ -2911,6 +2933,7 @@ TableConfigurationPanel.tableColumns=Table columnsCountToolbar.label.unknownCoun MyRequestsPanel.started = Started MyRequestsPanel.rejected = Rejected MyRequestsPanel.approved = Approved +MyRequestsPanel.inProgress = In progress MyRequestsPanel.name = Name PageSelfProfile.title=Edit profile PageSelfDashboard.title=Home @@ -2993,3 +3016,14 @@ PageResource.tab.content.entitlement=Entitlements PageResource.tab.content.generic=Generics ResourceContentTabPanel.search.repo=Repository ResourceContentTabPanel.search.resource=Resource +PagePreviewChanges.primaryChangesOne=Primary changes: {0} object +PagePreviewChanges.primaryChangesMore=Primary changes: {0} objects +PagePreviewChanges.secondaryChangesOne=Secondary changes: {0} object +PagePreviewChanges.secondaryChangesMore=Secondary changes: {0} objects +ScenePanel.object={0} object +ScenePanel.objects={0} objects +ScenePanel.item=Item +ScenePanel.oldValue=Old value +ScenePanel.newValue=New value +ScenePanel.value=Value + diff --git a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/CompositeRefinedObjectClassDefinition.java b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/CompositeRefinedObjectClassDefinition.java index bdd9fb71c8e..e8904dca783 100644 --- a/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/CompositeRefinedObjectClassDefinition.java +++ b/infra/common/src/main/java/com/evolveum/midpoint/common/refinery/CompositeRefinedObjectClassDefinition.java @@ -222,9 +222,8 @@ public ResourceType getResourceType() { return structuralObjectClassDefinition.getResourceType(); } - public PrismObjectDefinition getObjectDefinition() { - return structuralObjectClassDefinition.getObjectDefinition(); - } + // Do NOT override getObjectDefinition(). It will work by itself. + // overriding it will just complicate things. public ObjectClassComplexTypeDefinition getObjectClassDefinition() { return structuralObjectClassDefinition.getObjectClassDefinition(); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismProperty.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismProperty.java index 876ca0e5886..4c5fd97ee07 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismProperty.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismProperty.java @@ -241,6 +241,9 @@ public void setRealValue(Object realValue) { } public void addValues(Collection> pValuesToAdd) { + if (pValuesToAdd == null) { + return; + } for (PrismPropertyValue pValue: pValuesToAdd) { addValue(pValue); } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java index ab2ff5fd1e7..79058785a7d 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/PrismReferenceValue.java @@ -456,6 +456,9 @@ public String toString() { if (filter != null) { sb.append(", (filter)"); } + if (object != null) { + sb.append(", (object)"); + } sb.append(")"); return sb.toString(); } @@ -536,11 +539,17 @@ public String toHumanReadableString() { sb.append(DebugUtil.formatElementName(getTargetType())); sb.append(")"); } + if (targetName != null) { + sb.append("('").append(targetName).append("')"); + } if (getRelation() != null) { sb.append("["); sb.append(getRelation().getLocalPart()); sb.append("]"); } + if (getObject() != null) { + sb.append('*'); + } return sb.toString(); } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/DeltaBuilder.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/DeltaBuilder.java index 482cb2813cb..67d72bb0d87 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/DeltaBuilder.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/DeltaBuilder.java @@ -16,27 +16,9 @@ package com.evolveum.midpoint.prism.delta.builder; -import com.evolveum.midpoint.prism.ComplexTypeDefinition; -import com.evolveum.midpoint.prism.Containerable; -import com.evolveum.midpoint.prism.Item; -import com.evolveum.midpoint.prism.ItemDefinition; -import com.evolveum.midpoint.prism.Objectable; -import com.evolveum.midpoint.prism.PrismContainerDefinition; -import com.evolveum.midpoint.prism.PrismContainerValue; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismPropertyDefinition; -import com.evolveum.midpoint.prism.PrismPropertyValue; -import com.evolveum.midpoint.prism.PrismReferenceDefinition; -import com.evolveum.midpoint.prism.PrismReferenceValue; -import com.evolveum.midpoint.prism.PrismValue; -import com.evolveum.midpoint.prism.delta.ContainerDelta; -import com.evolveum.midpoint.prism.delta.ItemDelta; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.prism.delta.PropertyDelta; -import com.evolveum.midpoint.prism.delta.ReferenceDelta; +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.*; import com.evolveum.midpoint.prism.path.ItemPath; -import com.evolveum.midpoint.prism.query.builder.R_Filter; -import com.evolveum.midpoint.prism.query.builder.S_FilterEntryOrEmpty; import com.evolveum.midpoint.util.exception.SchemaException; import javax.xml.namespace.QName; @@ -55,17 +37,17 @@ * * @author mederly */ -public class DeltaBuilder implements S_ItemEntry, S_MaybeDelete, S_ValuesEntry { +public class DeltaBuilder implements S_ItemEntry, S_MaybeDelete, S_ValuesEntry { - final private Class objectClass; + final private Class objectClass; final private ComplexTypeDefinition containerCTD; final private PrismContext prismContext; // BEWARE - although these are final, their content may (and does) vary. Not much clean. - final List deltas; + final List> deltas; final ItemDelta currentDelta; - private DeltaBuilder(Class objectClass, PrismContext prismContext) throws SchemaException { + private DeltaBuilder(Class objectClass, PrismContext prismContext) throws SchemaException { this.objectClass = objectClass; this.prismContext = prismContext; containerCTD = prismContext.getSchemaRegistry().findComplexTypeDefinitionByCompileTimeClass(this.objectClass); @@ -76,7 +58,7 @@ private DeltaBuilder(Class objectClass, PrismContext prism currentDelta = null; } - public DeltaBuilder(Class objectClass, ComplexTypeDefinition containerCTD, PrismContext prismContext, List deltas, ItemDelta currentDelta) { + public DeltaBuilder(Class objectClass, ComplexTypeDefinition containerCTD, PrismContext prismContext, List> deltas, ItemDelta currentDelta) { this.objectClass = objectClass; this.containerCTD = containerCTD; this.prismContext = prismContext; @@ -84,7 +66,7 @@ public DeltaBuilder(Class objectClass, ComplexTypeDefiniti this.currentDelta = currentDelta; } - public Class getObjectClass() { + public Class getObjectClass() { return objectClass; } @@ -92,8 +74,8 @@ public PrismContext getPrismContext() { return prismContext; } - public static S_ItemEntry deltaFor(Class objectClass, PrismContext prismContext) throws SchemaException { - return new DeltaBuilder(objectClass, prismContext); + public static S_ItemEntry deltaFor(Class objectClass, PrismContext prismContext) throws SchemaException { + return new DeltaBuilder(objectClass, prismContext); } @Override @@ -127,21 +109,22 @@ public S_ValuesEntry item(ItemPath path, ItemDefinition definition) { } else { throw new IllegalStateException("Unsupported definition type: " + definition); } - List newDeltas = deltas; + List> newDeltas = deltas; if (currentDelta != null) { newDeltas.add(currentDelta); } return new DeltaBuilder(objectClass, containerCTD, prismContext, newDeltas, newDelta); } + // TODO fix this after ObjectDelta is changed to accept Containerable @Override public ObjectDelta asObjectDelta(String oid) { - return ObjectDelta.createModifyDelta(oid, getAllDeltas(), objectClass, prismContext); + return ObjectDelta.createModifyDelta(oid, getAllDeltas(), (Class) objectClass, prismContext); } @Override public ItemDelta asItemDelta() { - List allDeltas = getAllDeltas(); + List> allDeltas = getAllDeltas(); if (allDeltas.size() > 1) { throw new IllegalStateException("Too many deltas to fit into item delta: " + allDeltas.size()); } else if (allDeltas.size() == 1) { @@ -152,11 +135,11 @@ public ItemDelta asItemDelta() { } @Override - public List asItemDeltas() { + public List> asItemDeltas() { return getAllDeltas(); } - private List getAllDeltas() { + private List> getAllDeltas() { if (currentDelta != null) { deltas.add(currentDelta); } @@ -165,65 +148,107 @@ private List getAllDeltas() { @Override public S_MaybeDelete add(Object... realValues) { - checkNullMisuse(realValues); for (Object v : realValues) { - currentDelta.addValueToAdd(toPrismValue(currentDelta, v)); + if (v != null) { + currentDelta.addValueToAdd(toPrismValue(currentDelta, v)); + } } return this; } @Override public S_MaybeDelete add(PrismValue... values) { - currentDelta.addValuesToAdd(values); + for (PrismValue v : values) { + if (v != null) { + currentDelta.addValueToAdd(v); + } + } + return this; + } + + @Override + public S_MaybeDelete add(Collection values) { + for (PrismValue v : values) { + if (v != null) { + currentDelta.addValueToAdd(v); + } + } return this; } @Override public S_ItemEntry delete(Object... realValues) { - checkNullMisuse(realValues); for (Object v : realValues) { - currentDelta.addValueToDelete(toPrismValue(currentDelta, v)); + if (v != null) { + currentDelta.addValueToDelete(toPrismValue(currentDelta, v)); + } } return this; } - protected void checkNullMisuse(Object[] realValues) { - if (realValues.length == 1 && realValues[0] == null) { - throw new IllegalArgumentException("NULL value should be represented as no value, not as 'null'"); +// protected void checkNullMisuse(Object[] realValues) { +// if (realValues.length == 1 && realValues[0] == null) { +// throw new IllegalArgumentException("NULL value should be represented as no value, not as 'null'"); +// } +// } + + @Override + public S_ItemEntry delete(PrismValue... values) { + for (PrismValue v : values) { + if (v != null) { + currentDelta.addValueToDelete(v); + } } + return this; } @Override - public S_ItemEntry delete(PrismValue... values) { - currentDelta.addValuesToDelete(values); + public S_ItemEntry delete(Collection values) { + for (PrismValue v : values) { + if (v != null) { + currentDelta.addValueToDelete(v); + } + } return this; } @Override public S_ItemEntry replace(Object... realValues) { - checkNullMisuse(realValues); List prismValues = new ArrayList<>(); for (Object v : realValues) { - prismValues.add(toPrismValue(currentDelta, v)); + if (v != null) { + prismValues.add(toPrismValue(currentDelta, v)); + } } currentDelta.setValuesToReplace(prismValues); return this; } @Override - public S_ItemEntry replace(Collection values) { - currentDelta.setValuesToReplace(values); + public S_ItemEntry replace(Collection values) { + List prismValues = new ArrayList<>(); + for (PrismValue v : values) { + if (v != null) { + prismValues.add(v); + } + } + currentDelta.setValuesToReplace(prismValues); return this; } @Override public S_ItemEntry replace(PrismValue... values) { - checkNullMisuse(values); - currentDelta.setValuesToReplace(values); + List prismValues = new ArrayList<>(); + for (PrismValue v : values) { + if (v != null) { + prismValues.add(v); + } + } + currentDelta.setValuesToReplace(prismValues); return this; } - private PrismValue toPrismValue(ItemDelta currentDelta, Object v) { + private PrismValue toPrismValue(ItemDelta currentDelta, Object v) { ItemDefinition definition = currentDelta.getDefinition(); if (definition instanceof PrismPropertyDefinition) { return new PrismPropertyValue<>(v); diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/S_ItemEntry.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/S_ItemEntry.java index 0ac616af71e..57bd3c83b8e 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/S_ItemEntry.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/S_ItemEntry.java @@ -34,8 +34,8 @@ public interface S_ItemEntry { S_ValuesEntry item(ItemPath path); S_ValuesEntry item(ItemPath path, ItemDefinition itemDefinition); - ObjectDelta asObjectDelta(String oid); - ItemDelta asItemDelta(); - List asItemDeltas(); + ObjectDelta asObjectDelta(String oid); + ItemDelta asItemDelta(); + List> asItemDeltas(); } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/S_ValuesEntry.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/S_ValuesEntry.java index bc706e3a258..d1a8860f9d2 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/S_ValuesEntry.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/delta/builder/S_ValuesEntry.java @@ -27,10 +27,12 @@ public interface S_ValuesEntry { S_MaybeDelete add(Object... realValues); S_MaybeDelete add(PrismValue... values); + S_MaybeDelete add(Collection values); S_ItemEntry delete(Object... realValues); S_ItemEntry delete(PrismValue... values); + S_ItemEntry delete(Collection values); S_ItemEntry replace(Object... realValues); S_ItemEntry replace(PrismValue... values); - S_ItemEntry replace(Collection values); // TODO + S_ItemEntry replace(Collection values); } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java index 97b84ee789e..d139f04feec 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/path/ItemPath.java @@ -413,6 +413,15 @@ public static QName asSingleName(ItemPath path) { return path != null ? path.asSingleName() : null; } + public static ItemPath[] asPathArray(QName... names) { + ItemPath[] paths = new ItemPath[names.length]; + int i = 0; + for (QName name : names) { + paths[i++] = new ItemPath(name); + } + return paths; + } + public enum CompareResult { EQUIVALENT, SUPERPATH, diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/polystring/PolyString.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/polystring/PolyString.java index f4fac057c56..577902c6660 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/polystring/PolyString.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/polystring/PolyString.java @@ -257,4 +257,8 @@ public void checkConsistence() { public static PolyString toPolyString(PolyStringType value) { return value != null ? value.toPolyString() : null; } + + public static PolyStringType toPolyStringType(PolyString value) { + return value != null ? new PolyStringType(value) : null; + } } diff --git a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ObjectQuery.java b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ObjectQuery.java index 348ca01d20d..21a61e23048 100644 --- a/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ObjectQuery.java +++ b/infra/prism/src/main/java/com/evolveum/midpoint/prism/query/ObjectQuery.java @@ -186,4 +186,26 @@ public void addFilter(ObjectFilter objectFilter) { setFilter(AndFilter.createAnd(objectFilter, filter)); } } + + // use when offset/maxSize is expected + public Integer getOffset() { + if (paging == null) { + return null; + } + if (paging.getCookie() != null) { + throw new UnsupportedOperationException("Paging cookie is not supported here."); + } + return paging.getOffset(); + } + + // use when offset/maxSize is expected + public Integer getMaxSize() { + if (paging == null) { + return null; + } + if (paging.getCookie() != null) { + throw new UnsupportedOperationException("Paging cookie is not supported here."); + } + return paging.getMaxSize(); + } } diff --git a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/PolyStringType.java b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/PolyStringType.java index 7f8da401fb1..d44b8d5a28a 100644 --- a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/PolyStringType.java +++ b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/PolyStringType.java @@ -531,6 +531,8 @@ public boolean equals(Object obj) { return false; return true; } - - + + public static PolyStringType fromOrig(String name) { + return name != null ? new PolyStringType(name) : null; + } } diff --git a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ProtectedStringType.java b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ProtectedStringType.java index 9a079d7a99b..076f749152a 100644 --- a/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ProtectedStringType.java +++ b/infra/prism/src/main/java/com/evolveum/prism/xml/ns/_public/types_3/ProtectedStringType.java @@ -67,7 +67,9 @@ public byte[] getClearBytes() { @Override public void setClearBytes(byte[] bytes) { - setClearValue(bytesToString(bytes)); + if (bytes != null) { + setClearValue(bytesToString(bytes)); + } } @Override diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/GetOperationOptions.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/GetOperationOptions.java index abcf5a028a3..fc6c632482c 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/GetOperationOptions.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/GetOperationOptions.java @@ -155,6 +155,23 @@ public static GetOperationOptions createResolve() { return opts; } + // TODO exact placement of this method + public static Collection> resolveItemsNamed(Object... items) { + Collection> rv = new ArrayList<>(items.length); + for (Object item : items) { + final ItemPath path; + if (item instanceof QName) { + path = new ItemPath((QName) item); + } else if (item instanceof ItemPath) { + path = ((ItemPath) item); + } else { + throw new IllegalArgumentException("item has to be QName or ItemPath but is " + item); + } + rv.add(SelectorOptions.create(path, createResolve())); + } + return rv; + } + public Boolean getNoFetch() { return noFetch; } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/MidPointPrismContextFactory.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/MidPointPrismContextFactory.java index 5452cb5906b..b81d5a22700 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/MidPointPrismContextFactory.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/MidPointPrismContextFactory.java @@ -153,11 +153,11 @@ private void registerBuiltinSchemas(SchemaRegistry schemaRegistry) throws Schema schemaRegistry.registerPrismSchemaResource("xml/ns/public/model/workflow/extension-3.xsd", "wf"); - schemaRegistry.registerPrismSchemaResource("xml/ns/public/model/workflow/common-forms-3.xsd", "wfcf", - com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.ObjectFactory.class.getPackage()); - - schemaRegistry.registerPrismSchemaResource("xml/ns/public/model/workflow/process-instance-state-3.xsd", "wfpis", - com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ObjectFactory.class.getPackage()); +// schemaRegistry.registerPrismSchemaResource("xml/ns/public/model/workflow/common-forms-3.xsd", "wfcf", +// com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.ObjectFactory.class.getPackage()); +// +// schemaRegistry.registerPrismSchemaResource("xml/ns/public/model/workflow/process-instance-state-3.xsd", "wfpis", +// com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ObjectFactory.class.getPackage()); schemaRegistry.registerPrismSchemaResource("xml/ns/public/model/scripting/scripting-3.xsd", "s", com.evolveum.midpoint.xml.ns._public.model.scripting_3.ObjectFactory.class.getPackage()); diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/SelectorOptions.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/SelectorOptions.java index 19f6ac7a0da..b714849a838 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/SelectorOptions.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/SelectorOptions.java @@ -28,10 +28,7 @@ import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.prism.path.ItemPathSegment; import com.evolveum.midpoint.prism.path.NameItemPathSegment; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.LookupTableType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; /** * @author semancik @@ -96,7 +93,7 @@ public static Collection> createCollection(T options, QNa } return optionsCollection; } - //endregion + //endregion //region Simple getters public ObjectSelector getSelector() { @@ -144,6 +141,7 @@ public static boolean hasToLoadPath(QName itemName, Collection T getValueFromFilter(List conditions, QName propertyName) - throws SchemaException { - ItemPath propertyPath = new ItemPath(propertyName); - for (ObjectFilter f : conditions) { - if (f instanceof EqualFilter && propertyPath.equivalent(((EqualFilter) f).getFullPath())) { - List values = ((EqualFilter) f).getValues(); - if (values.size() > 1) { - throw new SchemaException("More than one " + propertyName - + " defined in the search query."); - } - if (values.size() < 1) { - throw new SchemaException("Search query does not have specified " + propertyName + "."); - } + public static PrismValue getValueFromQuery(ObjectQuery query, QName itemName) throws SchemaException { + if (query != null) { + return getValueFromFilter(query.getFilter(), itemName); + } else { + return null; + } + } - return (T) ((PrismPropertyValue) values.get(0)).getValue(); - } - if (NaryLogicalFilter.class.isAssignableFrom(f.getClass())) { - T value = getValueFromFilter(((NaryLogicalFilter) f).getConditions(), propertyName); - if (value != null) { - return value; - } - } + public static Collection getValuesFromQuery(ObjectQuery query, QName itemName) throws SchemaException { + if (query != null) { + return getValuesFromFilter(query.getFilter(), itemName); + } else { + return null; } + } - return null; + private static PrismValue getValueFromFilter(ObjectFilter filter, QName itemName) throws SchemaException { + Collection values = getValuesFromFilter(filter, itemName); + if (values == null || values.size() == 0) { + return null; + } else if (values.size() > 1) { + throw new SchemaException("More than one " + itemName + " defined in the search query."); + } else { + return values.iterator().next(); + } } - @SuppressWarnings("unchecked") - public static String getResourceOidFromFilter(List conditions) - throws SchemaException { + private static Collection getValuesFromFilter(ObjectFilter filter, QName itemName) throws SchemaException { + ItemPath propertyPath = new ItemPath(itemName); + if (filter instanceof EqualFilter && propertyPath.equivalent(((EqualFilter) filter).getFullPath())) { + return ((EqualFilter) filter).getValues(); + } else if (filter instanceof RefFilter && propertyPath.equivalent(((RefFilter) filter).getFullPath())) { + return (Collection) ((RefFilter) filter).getValues(); + } else if (filter instanceof AndFilter) { + return getValuesFromFilter(((NaryLogicalFilter) filter).getConditions(), itemName); + } else if (filter instanceof TypeFilter) { + return getValuesFromFilter(((TypeFilter) filter).getFilter(), itemName); + } else { + return null; + } + } + private static Collection getValuesFromFilter(List conditions, QName propertyName) + throws SchemaException { for (ObjectFilter f : conditions) { - if (f instanceof RefFilter - && ShadowType.F_RESOURCE_REF.equals(((RefFilter) f).getDefinition().getName())) { - List values = (List) ((RefFilter) f).getValues(); - if (values.size() > 1) { - throw new SchemaException( - "More than one resource references defined in the search query."); - } - if (values.size() < 1) { - throw new SchemaException("Search query does not have specified resource reference."); - } - return values.get(0).getOid(); - } - if (NaryLogicalFilter.class.isAssignableFrom(f.getClass())) { - String resourceOid = getResourceOidFromFilter(((NaryLogicalFilter) f).getConditions()); - if (resourceOid != null) { - return resourceOid; - } + Collection values = getValuesFromFilter(f, propertyName); + if (values != null) { + return values; } } return null; } + private static String getResourceOidFromFilter(ObjectFilter filter) throws SchemaException { + PrismReferenceValue referenceValue = (PrismReferenceValue) getValueFromFilter(filter, ShadowType.F_RESOURCE_REF); + return referenceValue != null ? referenceValue.getOid() : null; + } + + private static T getPropertyRealValueFromFilter(ObjectFilter filter, QName propertyName) throws SchemaException { + PrismPropertyValue propertyValue = (PrismPropertyValue) getValueFromFilter(filter, propertyName); + return propertyValue != null ? propertyValue.getValue() : null; + } + public static ResourceShadowDiscriminator getCoordinates(ObjectFilter filter) throws SchemaException { - String resourceOid = null; - QName objectClass = null; - ShadowKindType kind = null; - String intent = null; - - if (filter instanceof AndFilter) { - List conditions = ((AndFilter) filter).getConditions(); - resourceOid = getResourceOidFromFilter(conditions); - objectClass = getValueFromFilter(conditions, ShadowType.F_OBJECT_CLASS); - kind = getValueFromFilter(conditions, ShadowType.F_KIND); - intent = getValueFromFilter(conditions, ShadowType.F_INTENT); - } + String resourceOid = getResourceOidFromFilter(filter); + QName objectClass = getPropertyRealValueFromFilter(filter, ShadowType.F_OBJECT_CLASS); + ShadowKindType kind = getPropertyRealValueFromFilter(filter, ShadowType.F_KIND); + String intent = getPropertyRealValueFromFilter(filter, ShadowType.F_INTENT); if (resourceOid == null) { throw new SchemaException("Resource not defined in a search query"); @@ -484,4 +480,96 @@ public static ResourceShadowDiscriminator getCoordinates(ObjectFilter filter) th coordinates.setObjectClass(objectClass); return coordinates; } + + public static FilterComponents factorOutQuery(ObjectQuery query, QName... names) { + return factorOutQuery(query, ItemPath.asPathArray(names)); + } + + public static FilterComponents factorOutQuery(ObjectQuery query, ItemPath... paths) { + return factorOutFilter(query != null ? query.getFilter() : null, paths); + } + + public static FilterComponents factorOutFilter(ObjectFilter filter, ItemPath... paths) { + FilterComponents components = new FilterComponents(); + factorOutFilter(components, simplify(filter), Arrays.asList(paths)); + return components; + } + + private static void factorOutFilter(FilterComponents filterComponents, ObjectFilter filter, List paths) { + if (filter instanceof EqualFilter) { + EqualFilter equalFilter = (EqualFilter) filter; + if (ItemPath.containsEquivalent(paths, equalFilter.getPath())) { + filterComponents.addToKnown(equalFilter.getPath(), equalFilter.getValues()); + } else { + filterComponents.addToRemainder(equalFilter); + } + } else if (filter instanceof RefFilter) { + RefFilter refFilter = (RefFilter) filter; + if (ItemPath.containsEquivalent(paths, refFilter.getPath())) { + filterComponents.addToKnown(refFilter.getPath(), refFilter.getValues()); + } else { + filterComponents.addToRemainder(refFilter); + } + } else if (filter instanceof AndFilter) { + for (ObjectFilter condition : ((AndFilter) filter).getConditions()) { + factorOutFilter(filterComponents, condition, paths); + } + } else if (filter instanceof TypeFilter) { + factorOutFilter(filterComponents, ((TypeFilter) filter).getFilter(), paths); + } else if (filter != null) { + filterComponents.addToRemainder(filter); + } else { + // nothing to do with a null filter + } + } + + public static class FilterComponents { + private Map> knownComponents = new HashMap<>(); + private List remainderClauses = new ArrayList<>(); + + public Map> getKnownComponents() { + return knownComponents; + } + + public ObjectFilter getRemainder() { + if (remainderClauses.size() == 0) { + return null; + } else if (remainderClauses.size() == 1) { + return remainderClauses.get(0); + } else { + return AndFilter.createAnd(remainderClauses); + } + } + + public void addToKnown(ItemPath path, List values) { + Map.Entry> entry = getKnownComponent(path); + if (entry != null) { + entry.setValue(CollectionUtils.intersection(entry.getValue(), values)); + } else { + knownComponents.put(path, values); + } + } + + public Map.Entry> getKnownComponent(ItemPath path) { + for (Map.Entry> entry : knownComponents.entrySet()) { + if (path.equivalent(entry.getKey())) { + return entry; + } + } + return null; + } + + public void addToRemainder(ObjectFilter filter) { + remainderClauses.add(filter); + } + + public boolean hasRemainder() { + return !remainderClauses.isEmpty(); + } + + public List getRemainderClauses() { + return remainderClauses; + } + + } } diff --git a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ObjectTypeUtil.java b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ObjectTypeUtil.java index 07426f51224..273cc13d128 100644 --- a/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ObjectTypeUtil.java +++ b/infra/schema/src/main/java/com/evolveum/midpoint/schema/util/ObjectTypeUtil.java @@ -159,11 +159,18 @@ public static String dump(ObjectType object) { } public static Object toShortString(ObjectReferenceType objectRef) { + return toShortString(objectRef, false); + } + + public static Object toShortString(ObjectReferenceType objectRef, boolean withName) { if (objectRef == null) { return "null"; } StringBuilder sb = new StringBuilder(); sb.append("objectRef oid=").append(objectRef.getOid()); + if (withName && objectRef.getTargetName() != null) { + sb.append(" name='").append(objectRef.getTargetName()).append("'"); + } if (objectRef.getType() != null) { sb.append(" type=").append(SchemaDebugUtil.prettyPrint(objectRef.getType())); } @@ -190,6 +197,9 @@ public static ObjectReferenceType createObjectRef(PrismReferenceValue prv) { } public static ObjectReferenceType createObjectRef(ObjectType objectType) { + if (objectType == null) { + return null; + } return createObjectRef(objectType.asPrismObject()); } @@ -381,11 +391,44 @@ public static PrismObject getParentObject(Containerable containerable) { return (PrismObject) parent3; } - public static List getAsObjectReferenceTypeList(PrismReference prismReference) throws SchemaException { + public static List objectReferenceListToPrismReferenceValues(Collection refList) throws SchemaException { + List rv = new ArrayList<>(); + for (ObjectReferenceType ref : refList) { + rv.add(ref.asReferenceValue()); + } + return rv; + } + + public static List getAsObjectReferenceTypeList(PrismReference prismReference) throws SchemaException { List rv = new ArrayList<>(); for (PrismReferenceValue prv : prismReference.getValues()) { rv.add(createObjectRef(prv.clone())); } return rv; } + + public static List referenceValueListToOidList(Collection referenceValues) { + List oids = new ArrayList<>(referenceValues.size()); + for (PrismReferenceValue referenceValue : referenceValues) { + oids.add(referenceValue.getOid()); + } + return oids; + } + + public static Objectable getObjectFromReference(ObjectReferenceType ref) { + if (ref == null) { + return null; + } + if (ref.asReferenceValue().getObject() == null) { + return null; + } + return ref.asReferenceValue().getObject().asObjectable(); + } + + public static PrismObject getPrismObjectFromReference(ObjectReferenceType ref) { + if (ref == null) { + return null; + } + return ref.asReferenceValue().getObject(); + } } \ No newline at end of file diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index e08b31e40cd..220f46f6413 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -1339,7 +1339,19 @@ - TODO + Model context of the operation that is to be executed within this task. + This is NOT a live information: it is a serialized form of a model context. + Currently there is a specialized task handler that takes this context, + unmarshalls and executes it. + + + + + + + Workflow context of the operation that is to be executed within this task. + Points to a process instance in a workflow engine, and to an externalized view + of its state. @@ -11459,9 +11471,9 @@ Container for ChangesRequested (focus primary delta and/or projection primary deltas). - - - + + + diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-workflows-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-workflows-3.xsd index e008f8854d2..1c6362219fa 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-workflows-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-workflows-3.xsd @@ -60,8 +60,6 @@ - + @@ -138,7 +136,7 @@ - + A condition controlling whether this scenario applies, i.e. whether a defined approval process should be started. @@ -349,400 +347,473 @@ - + - WorkItemType contains information about a human task (or a notification). + Workflow context of the operation that is to be executed. + Points to a process instance in a workflow engine, and to an externalized view + of its state. + + Beware, some attributes like process state or work items may not be always present. + + + - - - - - - - Internal identifier of a work item, assigned by the underlying workflow engine - (currently Activiti). MidPoint WorkItem is Activiti Task. So workItemId is - taskId. - - - - - - - Identifier of a process instance, to which this work item (activiti task) belongs. - - - - - - - Class name of change processor that manages workflow process instance that contains this work item. - - - - - - - User to which the work item is assigned. Other users do not see such a work item in their work lists. - - - tns:assigneeRef - - - - - - - User to which the work item is assigned. Other users do not see such a work item in their work lists. - - - tns:UserType - - - - - - - Users to which the work item MAY BE assigned. - - - tns:candidateUsersRef - - - - - - - Users to which the work item MAY BE assigned. - - - tns:UserType - - - - - - - Organizations/roles to users of which the work item MAY BE assigned. - - - tns:candidateRolesRef - - - - - - - tns:AbstractRoleType - - - - - - - - User who requested the respective operation was carried out. - - - tns:requesterRef - - - - - - - User who requested the respective operation was carried out. - - - tns:UserType - - - + + + + + Internal identifier of a process instance, assigned by the underlying workflow engine + (currently Activiti). + + + + + + + Name of the process definition, e.g. "ItemApproval". + + + + + + + Name of the process instance. It is defined by the code that starts + the process instance and should describe the purpose of the process + instance as precisely as possible. An example: "Approving adding Webmaster to JoeDoe". + + + + + + + Time when this process instance started. + + + + + + + Time when this process instance finished (if it did). + + + + + + + User who requested the respective operation was carried out. Stored in repository. + + + c:UserType + + + + + + + Object whose modification is to be approved. (Normally the same as task.objectRef but there can be differences + in cases when the object is only to be created.) TODO - think this through. + + + + + + + Target of assignment/association/etc that is to be approved. + + + + + + + User(s) who approved current operation. Stored in repository. + + + c:UserType + + + + + + + This property is put into model task (i.e. not wf root task). It points to the + wf root task - that's important e.g. in cases when wf root task is not a subtask + of the model task. + + + c:TaskType + + + + + + + Value of process variable "wfState" that should describe current state of + the process instance (e.g. "Request was approved by Engineering, passed now to + the Management Group"). + + + + + + + True if the result is APPROVED. False if REJECTED. Null if the result is not yet + known or if it something other than APPROVED or REJECTED ("answer" property + has to be set in such case). + + + + + + + Value of process variable "wfAnswer" that should describe overall outcome + of the process instance. + + + + + + + Contains name of class that manages this particular model operation ("change", thus "change processor"). + + + + + + + Contains name of class that provides an interface between wf process and midPoint ("process interface bean"). + + + + + + + State that is specific to a given change processor. + + + + + + + State that is specific to a given BPMN process. + + + + + + + Currently open work items for this process. + + + + + + + + + + Basic information on a user decision in context of a work item. - - - - Work item contents - i.e. the actual work that the user has - to do, along with all the necessary information. - It is stored as PrismObject, although, actually, it is always a - subtype of WorkItemContents, but this structure is defined in separate XSD file. - TODO consider moving all wf-related structures to that file - in order to allow correct references among them. - - - tns:contentsRef - - - - - - - tns:ObjectType - - - + This structure is meant to describe the outcome of a work items in various contexts, + although currently it is used only within the generalized item approval process. + + + + + + + tns:UserType + + + + + + + Boolean representation of the decision, if applicable. + True = approved, false = rejected, null = either unknown or not applicable. + + + + + + + String representation of the result. Used in cases where the result is not simple 'approved' or 'rejected'. + + + + + + + + - - - - Various implementation-level (activiti) data useful for diagnostics. - - - tns:trackingDataRef - - - - - - - tns:TrackingDataType - - - + + + + + + + Describes states that are specific to a given change processor. + + + + + + + + + + + TODO + + + + + + + + + - - - + - + - Various implementation-level (activiti) data about a work item, useful for diagnostics. + TODO - + - - - - Activiti task identifier - 100 - read - - - - - - - Process instance ID - 110 - read - - - - - - - Process execution ID - 120 - read - - - - - - - Task owner - 130 - read - - - - - - - Task assignee - 140 - - - - - - - Task candidates - 150 - - - - - - - Process definition key - 160 - - - - - - - Process definition ID - 170 - - - - - - - Related midPoint task - 200 - - - + - + - + + + + - Information about workflow process instance. + Describe states that are specific to a given BPMN process. + + + + - Beware, the list of work items (workItems) may not be always present. - It depends on situation, e.g. when retrieving list of process instances, we do not populate this attribute. - When retrieving specific instance, we usually do. + + + + + + + TODO - + - - - - Internal identifier of a process instance, assigned by the underlying workflow engine - (currently Activiti). - - - - - - - Time when this process instance started. - - - - - - - Time when this process instance finished (if it did). - - - - - - - Is the instance finished? (TODO consider removing this and deriving from endTimestamp...) - - - - - - - (Externalized) process instance state stored as PrismObject. - Actually, it is always a subtype of ProcessInstanceState, - but this structure is defined in separate XSD file. - TODO consider moving all wf-related structures to that file - in order to allow correct references among them. - - - tns:stateRef - - - - - - - tns:ObjectType - - - - - - - Work items that are part of this process instance. This attribute may or may not be filled-in. - - - tns:workItemsRef - - - - - - - tns:WorkItemType - - - + + - + - + + + + - Basic information on a user decision in context of a work item. + TODO + + + + + + + + - This structure is meant to describe the outcome of a work items in various contexts, - although currently it is used only within the generalized item approval process. + + + + WorkItemType contains information about a human task (or a notification). + + + - + + + + Internal identifier of a work item, assigned by the underlying workflow engine + (currently Activiti). MidPoint WorkItem is Activiti Task. So workItemId is + taskId. + + + + - Information on a user who has made this decision. + Descriptive name of the work item. E.g. "Assign role1 to user1". + + + + + + + When was the operation requested, i.e. when the approval process started? + + (Normally, this information is relevant at the task/wf-process level. + However we put it here to avoid fetching tasks when we want to display + work item list only.) + + + + + + + When was this work item created? + + + + + + + Task that wraps process instance this work item is part of. - tns:approverRef + tns:TaskType - + + + User to which the work item is assigned. Other users do not see such a work item in their work lists. + tns:UserType - + - The name of a user who has made this decision. Used as an optimization to avoid retrieving and storing whole UserType. + Users to which the work item MAY BE assigned. + + tns:UserType + + + + + Organizations/roles to users of which the work item MAY BE assigned. + + + tns:AbstractRoleType + + + + + + + Object that is being modified (added, deleted) by the operation requested. + Typically a user, but might be also a role, org, resource, etc. - + (Normally, this information is relevant at the task/wf-process level. + However we put it here to avoid fetching tasks when we want to display + work item list only.) + + + tns:ObjectType + + + + - Boolean representation of the decision, if applicable. - True = approved, false = rejected, null = either unknown or not applicable. + Object that is being attached to/detached from the object modified. + Typically a role but might be also a resource, org, ... or it might be null. + + (Normally, this information is relevant at the task/wf-process level. + However we put it here to avoid fetching tasks when we want to display + work item list only.) + + tns:ObjectType + - + - String representation of the result. Used in cases where the result is not simple 'approved' or 'rejected'. + Approver's decision (if known). - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + diff --git a/infra/schema/src/main/resources/xml/ns/public/model/workflow/common-forms-3.xsd b/infra/schema/src/main/resources/xml/ns/public/model/workflow/common-forms-3.xsd index bc9b5bb788f..103883e87db 100644 --- a/infra/schema/src/main/resources/xml/ns/public/model/workflow/common-forms-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/model/workflow/common-forms-3.xsd @@ -48,334 +48,334 @@ - - - - Parent type for work item contents - the information that gets presented to the user and item(s) that - are elicited from the user. - - - - - - - - - The core of the request: a form that presents the user with request-specific question - and asks for request-specific answer. - - - tns:questionFormRef - - - - - - - tns:QuestionFormType - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - Generic work item contents for any process that approves a change to an object. - It contains object state before and after the change, the change itself, - any related objects, and a request-specific "question form". - - - - - - - - - Object before requested modification. - - - tns:objectOldRef - - - - - - - c:ObjectType - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - Object after requested modification. - - - tns:objectNewRef - - - - - - - c:ObjectType - - - + + + + + + + + + + + + + + + + + - - - - Delta to be approved by this work item. - - - + + + + + + + - - - - Any objects related to the request. E.g. if the request is to assign a role to the user, - in this attribute there is the role that is actually to be assigned. + + + + + - Due to current prism limitations, max count is set to 1. - - - tns:relatedObjectRef - - - - - - - c:ObjectType - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - TODO - - - - - - - - + + + + + + + + + + + + - - - - TODO - - - - - - - - - Owner (focus) name - 100 - read - - - - - - - Assigned object to be approved - 110 - read - - - - - - - Time interval - 120 - read - - - - - - - Requester's comment - 130 - read - - - - - - - Your comment - 140 - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - TODO - - - - - - - - - Owner (focus) name - 100 - read - - - - - - - Assigned object - 110 - read - - - - - - - - Changes to be approved - 120 - read - - - - - - - Requester's comment - 130 - read - - - - - - - Your comment - 140 - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - TODO - - - - - - - - - Object to be added - 100 - read - - - - - - - Requester's comment - 110 - read - - - - - - - Your comment - 120 - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - TODO - - - - - - - - - Owner (focus) name - 100 - read - - - - - - - Entitlement to be added - 110 - read - - - - - - - Your comment - 140 - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/infra/schema/src/main/resources/xml/ns/public/model/workflow/extension-3.xsd b/infra/schema/src/main/resources/xml/ns/public/model/workflow/extension-3.xsd index 2cfbad48fd1..1fbdb922180 100644 --- a/infra/schema/src/main/resources/xml/ns/public/model/workflow/extension-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/model/workflow/extension-3.xsd @@ -43,200 +43,200 @@ schemaLocation="http://midpoint.evolveum.com/xml/ns/public/common/common-3"> - - - - Contains deltaIn(i), i.e. delta(s) that has to be approved. - Valid for PrimaryChangeProcessor only. - - DEPRECATED. Replaced by deltasToProcess. - - - false - 0 - -1 - - - - - - - - Contains deltaIn(i), i.e. delta(s) that has to be approved. - Valid for PrimaryChangeProcessor only. - - - false - 0 - 1 - - - - - - - - Contains deltaOut(i), i.e. delta(s) that are the result of the approval process. The most - common situation is that deltaOut(i) = either deltaIn(i) (if approved), - or null/empty delta (if rejected). - - Valid for PrimaryChangeProcessor only. - - DEPRECATED. Replaced by resultingDeltas. - - - false - 0 - -1 - - - - - - - - Contains deltaOut(i), i.e. delta(s) that are the result of the approval process. The most - common situation is that deltaOut(i) = either deltaIn(i) (if approved), - or null/empty delta (if rejected). - - Valid for PrimaryChangeProcessor only. - - - false - 0 - 1 - - - - - - - - Contains a set of approvers who approved the delta(s). The wf code should put here those approvers - that will be stored into approvers list in metadata when the operation is really executed. - - - false - 0 - -1 - c:UserType - - - - - - - - Contains relevant activiti process instance ID (when known). - - - true - 0 - 1 - - - - - - - - Just a flag whether the process instance related to the task has already finished (used e.g. to - determine if the shadowing handler should end or not). - - - false - 0 - 1 - - - - - - - - OID of workflow root task that is stored into original task in the context of which the model operation was called. - - - true - 0 - 1 - - - - - - - - Contains name of class that manages this particular model operation ("change", thus "change processor"). - See https://wiki.evolveum.com/display/midPoint/Workflow+Management. - - - true - 0 - 1 - - - - - - - - The name of a class that provides an interface between midPoint and activiti process. - See https://wiki.evolveum.com/display/midPoint/Workflow+Management. - - Valid for PrimaryChangeProcessor only. - - - true - 0 - 1 - - - - - - - - Contains history of process status messages. Such messages can contain any process-related - messages that should be visible to the user (e.g. "your request was approved by engineering group, - and is being sent to the management"). For simple processes, the status has mostly the value - "Workflow process instance has proceeded". In order to be able to sort these status messages - chronologically, each is prefixed by a timestamp (long value + formatted string value). - - Storing of these wfStatus values can be simply turned off in WfTaskUtil class. - - - false - 0 - -1 - - - - - - - - A dump of recent process instance variables (for diagnostic purposes). - - - false - 0 - 1 - - - - - - - - String representation of recent process instance information (for diagnostic purposes). - - - false - 0 - 1 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/infra/schema/src/main/resources/xml/ns/public/model/workflow/process-instance-state-3.xsd b/infra/schema/src/main/resources/xml/ns/public/model/workflow/process-instance-state-3.xsd index c544005e3d5..a5090d79b3a 100644 --- a/infra/schema/src/main/resources/xml/ns/public/model/workflow/process-instance-state-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/model/workflow/process-instance-state-3.xsd @@ -48,211 +48,211 @@ - - - - - - - Generic process instance state, common to all workflow processes. - - - - - - - - - Name of the process instance. It is defined by the code that starts - the process instance and should describe the purpose of the process - instance as precisely as possible. An example: "Approving adding Webmaster to JoeDoe". - - - - - - - When the particular process instance started. - - - - - - - OID of process instance shadowing task in midPoint. (Process variable midPointTaskOid). - - - - - - - Class name of the midPoint change processor that manages this particular change request. - (Process variable midPointChangeProcessor.) - - - - - - - OID of the change requester. (Process variable midPointRequesterOid.) - - - - - - - OID of the object being changed (if applicable). (Process variable midPointObjectOid.) - - - - - - - Value of process variable "wfState" that should describe current state of - the process instance (e.g. "Request was approved by Engineering, passed now to - the Management Group"). - - - - - - - Value of process variable "wfAnswer" that should describe overall outcome - of the process instance. - - - - - - - State that is specific to a given change processor. - - - - - - - State that is specific to a given BPMN process. - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - Marker class for classes that describe states that are specific to a given change processor. - - - - + + + + + + + + + + + - - - - - - - TODO - - - - - - - - - - tns:objectToBeAddedRef - - - - - - - tns:ObjectType - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - TODO - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - Marker class for classes that describe states that are specific to a given BPMN process. - - - - + + + + + + + + + + + - - - - - - - TODO - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - TODO - - - - - - - - + + + + + + + + + + + + + + + diff --git a/model/certification-api/src/main/java/com/evolveum/midpoint/certification/api/AccessCertificationEventListener.java b/model/certification-api/src/main/java/com/evolveum/midpoint/certification/api/AccessCertificationEventListener.java index c03f833ea9b..71b53992882 100644 --- a/model/certification-api/src/main/java/com/evolveum/midpoint/certification/api/AccessCertificationEventListener.java +++ b/model/certification-api/src/main/java/com/evolveum/midpoint/certification/api/AccessCertificationEventListener.java @@ -16,13 +16,11 @@ package com.evolveum.midpoint.certification.api; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCampaignType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationCaseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; import java.util.List; diff --git a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertCaseOperationsHelper.java b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertCaseOperationsHelper.java index ca914b24dd8..b1c895e6888 100644 --- a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertCaseOperationsHelper.java +++ b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertCaseOperationsHelper.java @@ -161,7 +161,7 @@ void recordDecision(AccessCertificationCampaignType campaign, long caseId, Acces new NameItemPathSegment(F_CASE), new IdItemPathSegment(caseId), new NameItemPathSegment(AccessCertificationCaseType.F_DECISION)); - Collection deltaList = new ArrayList<>(); + Collection> deltaList = new ArrayList<>(); // let's remove existing decision and add the new one if (existingDecision != null) { @@ -200,11 +200,11 @@ void recordDecision(AccessCertificationCampaignType campaign, long caseId, Acces } } - List getDeltasToCreateCases( + List> getDeltasToCreateCases( final AccessCertificationCampaignType campaign, AccessCertificationStageType stage, final CertificationHandler handler, final Task task, final OperationResult result) throws SchemaException, ObjectNotFoundException { - final List rv = new ArrayList<>(); + final List> rv = new ArrayList<>(); final String campaignShortName = ObjectTypeUtil.toShortString(campaign); @@ -317,12 +317,12 @@ private List createEmptyDecisionsForCase(List getDeltasToAdvanceCases(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, Task task, OperationResult result) + List> getDeltasToAdvanceCases(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, Task task, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException { LOGGER.trace("Advancing reviewers and timestamps for cases in {}", ObjectTypeUtil.toShortString(campaign)); final List caseList = queryHelper.searchCases(campaign.getOid(), null, null, result); - final List rv = new ArrayList<>(caseList.size()); + final List> rv = new ArrayList<>(caseList.size()); final int stageToBe = campaign.getStageNumber() + 1; @@ -413,8 +413,8 @@ List getDeltasToAdvanceCases(AccessCertificationCampaignType campaign } // computes outcomes at stage close (stage-level and overall) and creates appropriate deltas - List createOutcomeDeltas(AccessCertificationCampaignType campaign, OperationResult result) throws ObjectNotFoundException, SchemaException { - final List rv = new ArrayList<>(); + List> createOutcomeDeltas(AccessCertificationCampaignType campaign, OperationResult result) throws ObjectNotFoundException, SchemaException { + final List> rv = new ArrayList<>(); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Updating current outcome for cases in {}", ObjectTypeUtil.toShortString(campaign)); @@ -472,7 +472,7 @@ public void markCaseAsRemedied(String campaignOid, long caseId, Task task, Opera new NameItemPathSegment(AccessCertificationCaseType.F_REMEDIED_TIMESTAMP)), generalHelper.getCampaignObjectDefinition(), XmlTypeConverter.createXMLGregorianCalendar(new Date())); - updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, Arrays.asList(reviewRemediedDelta), task, parentResult); + updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, Arrays.>asList(reviewRemediedDelta), task, parentResult); } diff --git a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertUpdateHelper.java b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertUpdateHelper.java index 844ed253d70..a4dd157ba63 100644 --- a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertUpdateHelper.java +++ b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/AccCertUpdateHelper.java @@ -179,7 +179,7 @@ private String generateName(String prefix, int i) { public void recordLastCampaignIdUsed(String definitionOid, int lastIdUsed, Task task, OperationResult result) { try { - List modifications = DeltaBuilder.deltaFor(AccessCertificationDefinitionType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationDefinitionType.class, prismContext) .item(F_LAST_CAMPAIGN_ID_USED).replace(lastIdUsed) .asItemDeltas(); modifyObjectViaModel(AccessCertificationDefinitionType.class, definitionOid, modifications, task, result); @@ -192,7 +192,7 @@ public void recordLastCampaignIdUsed(String definitionOid, int lastIdUsed, Task //region ================================ Stage open ================================ - public List getDeltasForStageOpen(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, CertificationHandler handler, final Task task, OperationResult result) + public List> getDeltasForStageOpen(AccessCertificationCampaignType campaign, AccessCertificationStageType stage, CertificationHandler handler, final Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { Validate.notNull(campaign, "certificationCampaign"); Validate.notNull(campaign.getOid(), "certificationCampaign.oid"); @@ -204,7 +204,7 @@ public List getDeltasForStageOpen(AccessCertificationCampaignType cam ObjectTypeUtil.toShortString(campaign), stageNumber); } - final List rv = new ArrayList<>(); + final List> rv = new ArrayList<>(); if (stageNumber == 0) { rv.addAll(caseHelper.getDeltasToCreateCases(campaign, stage, handler, task, result)); } else { @@ -220,10 +220,10 @@ public List getDeltasForStageOpen(AccessCertificationCampaignType cam } // some bureaucracy... stage#, state, start time, triggers - List createDeltasToRecordStageOpen(AccessCertificationCampaignType campaign, AccessCertificationStageType newStage, Task task, + List> createDeltasToRecordStageOpen(AccessCertificationCampaignType campaign, AccessCertificationStageType newStage, Task task, OperationResult result) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { - final List itemDeltaList = new ArrayList<>(); + final List> itemDeltaList = new ArrayList<>(); final PropertyDelta stageNumberDelta = createStageNumberDelta(newStage.getNumber()); itemDeltaList.add(stageNumberDelta); @@ -312,7 +312,7 @@ void afterStageOpen(String campaignOid, AccessCertificationStageType newStage, T } if (newStage.getNumber() == 1 && campaign.getDefinitionRef() != null) { - List deltas = DeltaBuilder.deltaFor(AccessCertificationDefinitionType.class, prismContext) + List> deltas = DeltaBuilder.deltaFor(AccessCertificationDefinitionType.class, prismContext) .item(F_LAST_CAMPAIGN_STARTED_TIMESTAMP).replace(XmlTypeConverter.createXMLGregorianCalendar(new Date())) .asItemDeltas(); modifyObjectViaModel(AccessCertificationDefinitionType.class, campaign.getDefinitionRef().getOid(), deltas, task, result); @@ -332,22 +332,22 @@ void closeCampaign(AccessCertificationCampaignType campaign, Task task, Operatio ContainerDelta triggerDelta = createTriggerDeleteDelta(); PropertyDelta endDelta = createEndTimeDelta(XmlTypeConverter.createXMLGregorianCalendar(new Date())); modifyObjectViaModel(AccessCertificationCampaignType.class, campaign.getOid(), - Arrays.asList(stateDelta, stageNumberDelta, triggerDelta, endDelta), task, result); + Arrays.>asList(stateDelta, stageNumberDelta, triggerDelta, endDelta), task, result); AccessCertificationCampaignType updatedCampaign = refreshCampaign(campaign, task, result); LOGGER.info("Updated campaign state: {}", updatedCampaign.getState()); eventHelper.onCampaignEnd(updatedCampaign, task, result); if (campaign.getDefinitionRef() != null) { - List deltas = DeltaBuilder.deltaFor(AccessCertificationDefinitionType.class, prismContext) + List> deltas = DeltaBuilder.deltaFor(AccessCertificationDefinitionType.class, prismContext) .item(F_LAST_CAMPAIGN_CLOSED_TIMESTAMP).replace(XmlTypeConverter.createXMLGregorianCalendar(new Date())) .asItemDeltas(); modifyObjectViaModel(AccessCertificationDefinitionType.class, campaign.getDefinitionRef().getOid(), deltas, task, result); } } - List getDeltasForStageClose(AccessCertificationCampaignType campaign, OperationResult result) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { - List rv = caseHelper.createOutcomeDeltas(campaign, result); + List> getDeltasForStageClose(AccessCertificationCampaignType campaign, OperationResult result) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { + List> rv = caseHelper.createOutcomeDeltas(campaign, result); rv.add(createStateDelta(REVIEW_STAGE_DONE)); rv.add(createStageEndTimeDelta(campaign)); @@ -376,8 +376,8 @@ void afterStageClose(String campaignOid, Task task, OperationResult result) thro //region ================================ Auxiliary methods for delta processing ================================ - List createDeltasForStageNumberAndState(int number, AccessCertificationCampaignStateType state) { - final List rv = new ArrayList<>(); + List> createDeltasForStageNumberAndState(int number, AccessCertificationCampaignStateType state) { + final List> rv = new ArrayList<>(); rv.add(createStageNumberDelta(number)); rv.add(createStateDelta(state)); return rv; @@ -433,7 +433,7 @@ void addObject(ObjectType objectType, Task task, OperationResult result) throws */ } - void modifyObjectViaModel(Class objectClass, String oid, Collection itemDeltas, Task task, OperationResult result) throws ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException { + void modifyObjectViaModel(Class objectClass, String oid, Collection> itemDeltas, Task task, OperationResult result) throws ObjectAlreadyExistsException, SchemaException, ObjectNotFoundException { ObjectDelta objectDelta = ObjectDelta.createModifyDelta(oid, itemDeltas, objectClass, prismContext); try { ModelExecuteOptions options = ModelExecuteOptions.createRaw().setPreAuthorized(); diff --git a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java index ff1a4bef37a..759ed089283 100644 --- a/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java +++ b/model/certification-impl/src/main/java/com/evolveum/midpoint/certification/impl/CertificationManagerImpl.java @@ -208,7 +208,7 @@ public void openNextStage(String campaignOid, int requestedStageNumber, Task tas } else { final CertificationHandler handler = findCertificationHandler(campaign); final AccessCertificationStageType stage = updateHelper.createStage(campaign, currentStageNumber+1); - final List deltas = updateHelper.getDeltasForStageOpen(campaign, stage, handler, task, result); + final List> deltas = updateHelper.getDeltasForStageOpen(campaign, stage, handler, task, result); updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, deltas, task, result); updateHelper.afterStageOpen(campaignOid, stage, task, result); } @@ -251,7 +251,7 @@ public void closeCurrentStage(String campaignOid, int stageNumberToClose, Task t } else if (!IN_REVIEW_STAGE.equals(state)) { result.recordFatalError("Couldn't close review stage " + stageNumberToClose + " as it is currently not open"); } else { - List deltas = updateHelper.getDeltasForStageClose(campaign, result); + List> deltas = updateHelper.getDeltasForStageClose(campaign, result); updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, deltas, task, result); updateHelper.afterStageClose(campaignOid, task, result); } @@ -293,7 +293,7 @@ public void startRemediation(String campaignOid, Task task, OperationResult pare } else if (!REVIEW_STAGE_DONE.equals(state)) { result.recordFatalError("Couldn't start the remediation as the last stage was not properly closed."); } else { - List deltas = updateHelper.createDeltasForStageNumberAndState(lastStageNumber + 1, IN_REMEDIATION); + List> deltas = updateHelper.createDeltasForStageNumberAndState(lastStageNumber + 1, IN_REMEDIATION); updateHelper.modifyObjectViaModel(AccessCertificationCampaignType.class, campaignOid, deltas, task, result); if (CertCampaignTypeUtil.isRemediationAutomatic(campaign)) { diff --git a/model/model-api/pom.xml b/model/model-api/pom.xml index 4cc47db5257..3c6cfddb053 100644 --- a/model/model-api/pom.xml +++ b/model/model-api/pom.xml @@ -72,5 +72,9 @@ audit-api 3.4-SNAPSHOT - + + org.jetbrains + annotations-java5 + + diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java index 05cc1ce3f18..f8b864735d1 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelInteractionService.java @@ -15,25 +15,22 @@ */ package com.evolveum.midpoint.model.api; -import java.util.Collection; - import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.api.visualizer.Scene; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.DisplayableValue; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; -import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; /** * A service provided by the IDM Model that allows to improve the (user) interaction with the model. @@ -73,7 +70,11 @@ ModelContext previewChanges( Collection> deltas, ModelExecuteOptions options, Task task, OperationResult result) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException; - ModelContext unwrapModelContext(LensContextType wrappedContext, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException; + ModelContext previewChanges( + Collection> deltas, ModelExecuteOptions options, Task task, Collection listeners, OperationResult result) + throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException; + + ModelContext unwrapModelContext(LensContextType wrappedContext, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException; /** *

@@ -160,4 +161,10 @@ ModelContext previewChanges( * @return true if the password matches, false otherwise */ boolean checkPassword(String userOid, ProtectedStringType password, Task task, OperationResult parentResult) throws ObjectNotFoundException, SchemaException; + + // TEMPORARY + List visualizeDeltas(List> deltas, Task task, OperationResult result) throws SchemaException; + + @NotNull + Scene visualizeDelta(ObjectDelta delta, Task task, OperationResult result) throws SchemaException; } diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java index d86227fa36a..5fc9ec2bf11 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/ModelService.java @@ -87,6 +87,7 @@ public interface ModelService { static final String GET_OBJECT = CLASS_NAME_WITH_DOT + "getObject"; static final String SEARCH_OBJECTS = CLASS_NAME_WITH_DOT + "searchObjects"; static final String SEARCH_CONTAINERS = CLASS_NAME_WITH_DOT + "searchContainers"; + static final String COUNT_CONTAINERS = CLASS_NAME_WITH_DOT + "countContainers"; static final String COUNT_OBJECTS = CLASS_NAME_WITH_DOT + "countObjects"; static final String EXECUTE_CHANGES = CLASS_NAME_WITH_DOT + "executeChanges"; static final String EXECUTE_CHANGE = CLASS_NAME_WITH_DOT + "executeChange"; @@ -422,7 +423,7 @@ SearchResultList> searchObjects(Class t /** * Search for "sub-object" structures, i.e. containers. - * Currently, only one type of search is available: certification case search. + * Supported types are: AccessCertificationCaseType, WorkItemType. * * @param type * @param query @@ -437,6 +438,10 @@ SearchResultList searchContainers( Collection> options, Task task, OperationResult parentResult) throws SchemaException, SecurityViolationException, ConfigurationException, ObjectNotFoundException; + Integer countContainers(Class type, ObjectQuery query, Collection> options, + Task task, OperationResult parentResult) + throws SchemaException; + /** *

* Search for objects in iterative fashion (using callback). diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/WorkflowService.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/WorkflowService.java index 8f54bdf0c06..6cef0034099 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/WorkflowService.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/WorkflowService.java @@ -1,107 +1,28 @@ package com.evolveum.midpoint.model.api; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessInstanceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; - -import java.util.List; +import com.evolveum.midpoint.util.exception.SecurityViolationException; /** * @author mederly */ public interface WorkflowService { - /* - * Work items - * ========== - */ - - /** - * Counts Work Items related to a user. - * - * @param userOid OID of the user - * @param assigned whether to count assigned (true) or assignable (false) work items - * @param parentResult - * @return number of relevant work items - */ - int countWorkItemsRelatedToUser(String userOid, boolean assigned, OperationResult parentResult) throws SchemaException, ObjectNotFoundException; - - /** - * Lists work items related to a user. - * - * @param userOid OID of the user - * @param assigned whether to count assigned (true) or assignable (false) work items - * @param first - * @param count - * @param parentResult - * @return list of work items - */ - List listWorkItemsRelatedToUser(String userOid, boolean assigned, int first, int count, OperationResult parentResult) throws SchemaException, ObjectNotFoundException; - - /** - * Provides detailed information about a given work item (may be inefficient, so use with care). - * - * @param taskId - * @param parentResult - * @return - * @throws com.evolveum.midpoint.util.exception.ObjectNotFoundException - * @throws WorkflowException - */ - WorkItemType getWorkItemDetailsById(String workItemId, OperationResult parentResult) throws ObjectNotFoundException; - - /* - * Process instances - * ================= - */ - - int countProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, OperationResult parentResult); - - List listProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, int first, int count, OperationResult parentResult); - - WfProcessInstanceType getProcessInstanceByWorkItemId(String workItemId, OperationResult parentResult) throws ObjectNotFoundException; - - /** - * Returns information about a process instance. WorkItems attribute is filled-in only upon request! (see getWorkItems parameter) - * - * @param instanceId - * @param historic - * @param getWorkItems - * @param parentResult - * @return - * @throws ObjectNotFoundException - * @throws WorkflowException - */ - public WfProcessInstanceType getProcessInstanceById(String instanceId, boolean historic, boolean getWorkItems, OperationResult parentResult) throws ObjectNotFoundException; - - /* - * CHANGING THINGS - * =============== - */ - /** * Approves or rejects a work item (without supplying any further information). - * - * @param taskId identifier of activiti task backing the work item + * @param taskId identifier of activiti task backing the work item * @param decision true = approve, false = reject * @param parentResult + * @param comment */ - void approveOrRejectWorkItem(String workItemId, boolean decision, OperationResult parentResult); - - void approveOrRejectWorkItemWithDetails(String workItemId, PrismObject specific, boolean decision, OperationResult result); - - void completeWorkItemWithDetails(String workItemId, PrismObject specific, String decision, OperationResult parentResult); + void approveOrRejectWorkItem(String workItemId, boolean decision, String comment, OperationResult parentResult) throws SecurityViolationException; void stopProcessInstance(String instanceId, String username, OperationResult parentResult); void deleteProcessInstance(String instanceId, OperationResult parentResult); - void claimWorkItem(String workItemId, OperationResult parentResult); + void claimWorkItem(String workItemId, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException; - void releaseWorkItem(String workItemId, OperationResult parentResult); + void releaseWorkItem(String workItemId, OperationResult parentResult) throws ObjectNotFoundException, SecurityViolationException; } diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelProjectionContext.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelProjectionContext.java index 0d6c90e31cd..fc00506245c 100644 --- a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelProjectionContext.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/context/ModelProjectionContext.java @@ -17,6 +17,7 @@ import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; +import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; @@ -47,5 +48,6 @@ public interface ModelProjectionContext extends ModelElementContext * @see SynchronizationPolicyDecision */ public SynchronizationPolicyDecision getSynchronizationPolicyDecision(); - + + ObjectDelta getExecutableDelta() throws SchemaException; } diff --git a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/dto/ResourceSearchDto.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/Name.java similarity index 61% rename from gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/dto/ResourceSearchDto.java rename to model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/Name.java index 6b61de10bd2..72cdf7fcd90 100644 --- a/gui/admin-gui/src/main/java/com/evolveum/midpoint/web/page/admin/resources/dto/ResourceSearchDto.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/Name.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,24 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.evolveum.midpoint.web.page.admin.resources.dto; -import java.io.Serializable; +package com.evolveum.midpoint.model.api.visualizer; -/** - * @author shood - * */ -public class ResourceSearchDto implements Serializable{ +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.path.ItemPath; - public static final String F_TEXT = "text"; +import java.io.Serializable; - private String text; +/** + * Name of a scene or a scene item. + * + * @author mederly + */ +public interface Name extends Serializable { - public String getText() { - return text; - } + String getSimpleName(); + String getDisplayName(); + String getId(); + String getDescription(); - public void setText(String text) { - this.text = text; - } } diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/Scene.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/Scene.java new file mode 100644 index 00000000000..183eaf1ffdd --- /dev/null +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/Scene.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.api.visualizer; + +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.delta.ChangeType; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.util.DebugDumpable; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.List; + +/** + * @author mederly + */ +public interface Scene extends Serializable, DebugDumpable { + + Name getName(); + ChangeType getChangeType(); + + @NotNull List getPartialScenes(); + @NotNull List getItems(); + + boolean isOperational(); + + Scene getOwner(); + + /** + * Scene root path, relative to the owning scene root path. + */ + ItemPath getSourceRelPath(); + + ItemPath getSourceAbsPath(); + + /** + * Source container value where more details can be found. + * (For scenes that display object or value add.) + */ + PrismContainerValue getSourceValue(); + + PrismContainerDefinition getSourceDefinition(); + + /** + * Source object delta where more details can be found. + * (For scenes that display an object delta.) + */ + ObjectDelta getSourceDelta(); + +} diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneDeltaItem.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneDeltaItem.java new file mode 100644 index 00000000000..6acb879711e --- /dev/null +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneDeltaItem.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.api.visualizer; + +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.List; + +/** + * @author mederly + */ +public interface SceneDeltaItem extends SceneItem, Serializable { + + @NotNull List getOldValues(); + @NotNull List getAddedValues(); + @NotNull List getDeletedValues(); + @NotNull List getUnchangedValues(); + + /** + * Item delta (if applicable). It should contain the original path (not a relative one). + */ + ItemDelta getSourceDelta(); +} diff --git a/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneItem.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneItem.java new file mode 100644 index 00000000000..4445d1f03ba --- /dev/null +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneItem.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.api.visualizer; + +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.path.ItemPath; + +import java.io.Serializable; +import java.util.List; + +/** + * @author mederly + */ +public interface SceneItem extends Serializable { + + Name getName(); + List getNewValues(); + + boolean isOperational(); + + Item getSourceItem(); + + /** + * Item path, relative to the scene root path. + */ + ItemPath getSourceRelPath(); +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WfConstants.java b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneItemValue.java similarity index 68% rename from model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WfConstants.java rename to model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneItemValue.java index 7027e2b5532..3231d347ede 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WfConstants.java +++ b/model/model-api/src/main/java/com/evolveum/midpoint/model/api/visualizer/SceneItemValue.java @@ -1,24 +1,30 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl; - -/** - * @author mederly - */ -public class WfConstants { - -} +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.api.visualizer; + +import com.evolveum.midpoint.prism.PrismValue; + +import java.io.Serializable; + +/** + * @author mederly + */ + +public interface SceneItemValue extends Serializable { + String getText(); + PrismValue getSourceValue(); +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelObjectResolver.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelObjectResolver.java index 89920bc9675..2fae9fcdecb 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelObjectResolver.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/ModelObjectResolver.java @@ -23,6 +23,8 @@ import com.evolveum.midpoint.model.api.hooks.ReadHook; import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.wf.api.WorkflowManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -51,10 +53,6 @@ import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType; /** * @author semancik @@ -76,6 +74,9 @@ public class ModelObjectResolver implements ObjectResolver { @Autowired private transient TaskManager taskManager; + @Autowired(required = false) + private transient WorkflowManager workflowManager; + @Autowired(required = false) private transient HookRegistry hookRegistry; @@ -150,6 +151,7 @@ public T getObject(Class clazz, String oid, Collection try { PrismObject object = null; ObjectTypes.ObjectManager manager = ObjectTypes.getObjectManagerForClass(clazz); + final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); switch (manager) { case PROVISIONING: object = provisioning.getObject(clazz, oid, options, task, result); @@ -164,6 +166,9 @@ public T getObject(Class clazz, String oid, Collection throw new SystemException("Got null result from taskManager.getObject while looking for "+clazz.getSimpleName() +" with OID "+oid+"; using task manager implementation "+taskManager.getClass().getName()); } + if (workflowManager != null && TaskType.class.isAssignableFrom(clazz) && !GetOperationOptions.isRaw(rootOptions) && !GetOperationOptions.isNoFetch(rootOptions)) { + workflowManager.augmentTaskObject(object, options, task, result); + } break; default: object = cacheRepositoryService.getObject(clazz, oid, options, result); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java index 62218d49575..d6bca908d1e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelController.java @@ -38,8 +38,7 @@ import com.evolveum.midpoint.model.api.hooks.ReadHook; import com.evolveum.midpoint.model.impl.scripting.ExecutionContext; import com.evolveum.midpoint.model.impl.scripting.ScriptingExpressionEvaluator; -import com.evolveum.midpoint.prism.Containerable; -import com.evolveum.midpoint.prism.PrismConstants; +import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.query.*; import com.evolveum.midpoint.schema.util.ObjectQueryUtil; @@ -73,11 +72,6 @@ import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; import com.evolveum.midpoint.model.impl.lens.projector.Projector; import com.evolveum.midpoint.model.impl.util.Utils; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; -import com.evolveum.midpoint.prism.PrismReference; -import com.evolveum.midpoint.prism.PrismReferenceValue; import com.evolveum.midpoint.prism.crypto.Protector; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.path.ItemPath; @@ -148,7 +142,7 @@ public class ModelController implements ModelService, TaskService, WorkflowServi public static final String CREATE_ACCOUNT = CLASS_NAME_WITH_DOT + "createAccount"; public static final String UPDATE_ACCOUNT = CLASS_NAME_WITH_DOT + "updateAccount"; public static final String PROCESS_USER_TEMPLATE = CLASS_NAME_WITH_DOT + "processUserTemplate"; - + private static final Trace LOGGER = TraceManager.getTrace(ModelController.class); @Autowired @@ -187,37 +181,37 @@ public class ModelController implements ModelService, TaskService, WorkflowServi @Autowired private ScriptingExpressionEvaluator scriptingExpressionEvaluator; - + @Autowired private ChangeExecutor changeExecutor; @Autowired SystemConfigurationHandler systemConfigurationHandler; - + @Autowired private AuditService auditService; - + @Autowired private SecurityEnforcer securityEnforcer; - + @Autowired private UserProfileService userProfileService; - + @Autowired Projector projector; - + @Autowired Protector protector; - + @Autowired ModelDiagController modelDiagController; - + @Autowired ContextFactory contextFactory; - + @Autowired private SchemaTransformer schemaTransformer; - + public ModelObjectResolver getObjectResolver() { return objectResolver; } @@ -253,8 +247,8 @@ public PrismObject getObject(Class clazz, String oi result.addParam("class", clazz); GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - - try { + + try { if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); } @@ -262,9 +256,9 @@ public PrismObject getObject(Class clazz, String oi ref.setOid(oid); ref.setType(ObjectTypes.getObjectType(clazz).getTypeQName()); Utils.clearRequestee(task); - + object = objectResolver.getObject(clazz, oid, options, task, result).asPrismObject(); - + schemaTransformer.applySchemasAndSecurity(object, rootOptions, null, task, result); resolve(object, options, task, result); @@ -294,21 +288,28 @@ public PrismObject getObject(Class clazz, String oi QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); RepositoryCache.exit(); } - + result.cleanupResult(); - + return object; } protected void resolve(PrismObject object, Collection> options, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException { - if (object == null || options == null) { + if (object == null) { return; } + resolve(object.asObjectable(), options, task, result); + } + protected void resolve(Containerable containerable, Collection> options, + Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException { + if (containerable == null || options == null) { + return; + } for (SelectorOptions option: options) { - try{ - resolve(object, option, task, result); + try { + resolve(containerable, option, task, result); } catch(ObjectNotFoundException ex){ result.recordFatalError(ex.getMessage(), ex); return; @@ -316,7 +317,7 @@ protected void resolve(PrismObject object, Collection object, SelectorOptions option, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException { + private void resolve(Containerable object, SelectorOptions option, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException { if (!GetOperationOptions.isResolve(option.getOptions())) { return; } @@ -329,30 +330,41 @@ private void resolve(PrismObject object, SelectorOptions resolve(object, path, option, task, result); } - private void resolve(PrismObject object, ItemPath path, SelectorOptions option, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException { + private void resolve(Containerable containerable, ItemPath path, SelectorOptions option, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, SecurityViolationException, ConfigurationException { if (path == null || path.isEmpty()) { return; } ItemPathSegment first = path.first(); ItemPath rest = path.rest(); QName refName = ItemPath.getName(first); - PrismReference reference = object.findReferenceByCompositeObjectElementName(refName); + PrismContainerValue containerValue = containerable.asPrismContainerValue(); + + PrismReference reference = containerValue.findReferenceByCompositeObjectElementName(refName); if (reference == null) { - // alternatively look up by reference name (e.g. linkRef) - reference = object.findReference(refName); - if (reference == null) { - return;//throw new SchemaException("Cannot resolve: No reference "+refName+" in "+object); - } + reference = containerValue.findReference(refName); // alternatively look up by reference name (e.g. linkRef) } - for (PrismReferenceValue refVal: reference.getValues()) { - PrismObject refObject = refVal.getObject(); - if (refObject == null) { - refObject = objectResolver.resolve(refVal, object.toString(), option.getOptions(), task, result); - schemaTransformer.applySchemasAndSecurity(refObject, option.getOptions(), null, task, result); - refVal.setObject(refObject); + if (reference == null) { + if (rest.isEmpty()) { + return; } - if (!rest.isEmpty()) { - resolve(refObject, rest, option, task, result); + PrismContainer childContainer = containerValue.findContainer(refName); // it may be e.g. taskRef -> workflowContext -> requesterRef + if (childContainer == null) { + return; + } + for (PrismContainerValue pcv : childContainer.getValues()) { + resolve(pcv.asContainerable(), rest, option, task, result); + } + } else { + for (PrismReferenceValue refVal : reference.getValues()) { + PrismObject refObject = refVal.getObject(); + if (refObject == null) { + refObject = objectResolver.resolve(refVal, containerable.toString(), option.getOptions(), task, result); + schemaTransformer.applySchemasAndSecurity(refObject, option.getOptions(), null, task, result); + refVal.setObject(refObject); + } + if (!rest.isEmpty()) { + resolve(refObject.asObjectable(), rest, option, task, result); + } } } } @@ -786,28 +798,17 @@ public SearchResultList> searchObjects(Cla switch (searchProvider) { case REPOSITORY: list = cacheRepositoryService.searchObjects(type, query, options, result); break; case PROVISIONING: list = provisioning.searchObjects(type, query, options, task, result); break; - case TASK_MANAGER: list = taskManager.searchObjects(type, query, options, result); break; - case WORKFLOW: throw new UnsupportedOperationException(); + case TASK_MANAGER: + list = taskManager.searchObjects(type, query, options, result); + if (workflowManager != null && TaskType.class.isAssignableFrom(type) && !GetOperationOptions.isRaw(rootOptions) && !GetOperationOptions.isNoFetch(rootOptions)) { + workflowManager.augmentTaskObjectList(list, options, task, result); + } + break; default: throw new AssertionError("Unexpected search provider: " + searchProvider); } result.computeStatus(); result.cleanupResult(); - } catch (CommunicationException e) { - processSearchException(e, rootOptions, searchProvider, result); - throw e; - } catch (ConfigurationException e) { - processSearchException(e, rootOptions, searchProvider, result); - throw e; - } catch (ObjectNotFoundException e) { - processSearchException(e, rootOptions, searchProvider, result); - throw e; - } catch (SchemaException e) { - processSearchException(e, rootOptions, searchProvider, result); - throw e; - } catch (SecurityViolationException e) { - processSearchException(e, rootOptions, searchProvider, result); - throw e; - } catch (RuntimeException e) { + } catch (CommunicationException | ConfigurationException | SchemaException | SecurityViolationException | RuntimeException | ObjectNotFoundException e) { processSearchException(e, rootOptions, searchProvider, result); throw e; } finally { @@ -850,17 +851,31 @@ public SearchResultList searchContainers( ModelUtils.validatePaging(query.getPaging()); } - if (!AccessCertificationCaseType.class.equals(type)) { - throw new UnsupportedOperationException("searchContainers method is currently supported only for AccessCertificationCaseType class"); + final boolean isCase = AccessCertificationCaseType.class.equals(type); + final boolean isWorkItem = WorkItemType.class.equals(type); + + if (!isCase && !isWorkItem) { + throw new UnsupportedOperationException("searchContainers method is currently supported only for AccessCertificationCaseType and WorkItemType classes"); } - GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); - OperationResult result = parentResult.createSubresult(SEARCH_CONTAINERS); + final OperationResult result = parentResult.createSubresult(SEARCH_CONTAINERS); result.addParams(new String[] { "type", "query", "paging" }, type, query, (query != null ? query.getPaging() : "undefined")); - query = preProcessSubobjectQuerySecurity(AccessCertificationCaseType.class, AccessCertificationCampaignType.class, query); + + final ObjectTypes.ObjectManager manager; + if (isCase) { + query = preProcessSubobjectQuerySecurity(AccessCertificationCaseType.class, AccessCertificationCampaignType.class, query); + manager = ObjectTypes.ObjectManager.REPOSITORY; + } else if (isWorkItem) { + query = preProcessWorkItemSecurity(query); + manager = ObjectTypes.ObjectManager.WORKFLOW; + } else { + throw new IllegalStateException(); + } + if (isFilterNone(query, result)) { return new SearchResultList(new ArrayList<>()); } @@ -875,11 +890,15 @@ public SearchResultList searchContainers( if (GetOperationOptions.isRaw(rootOptions)) { // MID-2218 QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(true); } - list = cacheRepositoryService.searchContainers(type, query, options, result); + switch (manager) { + case REPOSITORY: list = cacheRepositoryService.searchContainers(type, query, options, result); break; + case WORKFLOW: list = workflowManager.searchContainers(type, query, options, result); break; + default: throw new IllegalStateException(); + } result.computeStatus(); result.cleanupResult(); } catch (SchemaException|RuntimeException e) { - processSearchException(e, rootOptions, ObjectTypes.ObjectManager.REPOSITORY, result); + processSearchException(e, rootOptions, manager, result); throw e; } finally { QNameUtil.setTemporarilyTolerateUndeclaredPrefixes(false); @@ -892,18 +911,98 @@ public SearchResultList searchContainers( list = new SearchResultList(new ArrayList<>()); } - // TODO implement read hook, if necessary - // TODO implement resolve option, if necessary + for (T object : list) { + // TODO implement read hook, if necessary + resolve(object, options, task, result); + } } finally { RepositoryCache.exit(); } - list = schemaTransformer.applySchemasAndSecurityToContainers(list, AccessCertificationCampaignType.class, - AccessCertificationCampaignType.F_CASE, rootOptions, null, task, result); + if (isCase) { + list = schemaTransformer.applySchemasAndSecurityToContainers(list, AccessCertificationCampaignType.class, + AccessCertificationCampaignType.F_CASE, rootOptions, null, task, result); + } else if (isWorkItem) { + // TODO implement security post processing for WorkItems + } else { + throw new IllegalStateException(); + } return list; } + @Override + public Integer countContainers( + Class type, ObjectQuery query, Collection> options, + Task task, OperationResult parentResult) throws SchemaException { + + Validate.notNull(type, "Container value type must not be null."); + Validate.notNull(parentResult, "Result type must not be null."); + + final boolean isWorkItem = WorkItemType.class.equals(type); + + if (!isWorkItem) { + throw new UnsupportedOperationException("countContainers method is currently supported only for WorkItemType classes"); + } + + final GetOperationOptions rootOptions = SelectorOptions.findRootOptions(options); + + final OperationResult result = parentResult.createSubresult(SEARCH_CONTAINERS); + result.addParams(new String[] { "type", "query"}, type, query); + + + final ObjectTypes.ObjectManager manager; + if (isWorkItem) { + query = preProcessWorkItemSecurity(query); + manager = ObjectTypes.ObjectManager.WORKFLOW; + } else { + throw new IllegalStateException(); + } + + if (isFilterNone(query, result)) { + return 0; + } + + Integer count; + try { + RepositoryCache.enter(); + + logQuery(query); + + try { + switch (manager) { + //case REPOSITORY: list = cacheRepositoryService.searchContainers(type, query, options, result); break; + case WORKFLOW: count = workflowManager.countContainers(type, query, options, result); break; + default: throw new IllegalStateException(); + } + result.computeStatus(); + result.cleanupResult(); + } catch (SchemaException|RuntimeException e) { + processSearchException(e, rootOptions, manager, result); + throw e; + } finally { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace(result.dump(false)); + } + } + } finally { + RepositoryCache.exit(); + } + + return count; + } + + + private ObjectQuery preProcessWorkItemSecurity(ObjectQuery query) { + /* + * TODO implement something like: + * - if then no change + * - if then add "assignee == " or "assignable == " (TODO) + * - else + */ + return query; + } + protected boolean isFilterNone(ObjectQuery query, OperationResult result) { if (query != null && query.getFilter() != null && query.getFilter() instanceof NoneFilter) { LOGGER.trace("Security denied the search"); @@ -981,8 +1080,7 @@ public boolean handle(PrismObject object, OperationResult parentResult) { switch (searchProvider) { case REPOSITORY: metadata = cacheRepositoryService.searchObjectsIterative(type, query, internalHandler, options, false, result); break; // TODO move strictSequential flag to model API in some form case PROVISIONING: metadata = provisioning.searchObjectsIterative(type, query, options, internalHandler, task, result); break; - case TASK_MANAGER: throw new UnsupportedOperationException("searchIterative in task manager is currently not supported"); - case WORKFLOW: throw new UnsupportedOperationException("searchIterative in task manager is currently not supported"); + case TASK_MANAGER: throw new UnsupportedOperationException("searchObjectsIterative in task manager is currently not supported"); default: throw new AssertionError("Unexpected search provider: " + searchProvider); } result.computeStatusIfUnknown(); @@ -1024,7 +1122,7 @@ private void processSearchException(Exception e, GetOperationOptions rootOptions case REPOSITORY: message = "Couldn't search objects in repository"; break; case PROVISIONING: message = "Couldn't search objects in provisioning"; break; case TASK_MANAGER: message = "Couldn't search objects in task manager"; break; - case WORKFLOW: message = "Couldn't search objects in workflow module"; break; + case WORKFLOW: message = "Couldn't search objects in workflow engine"; break; default: message = "Couldn't search objects"; break; // should not occur } LoggingUtils.logException(LOGGER, message, e); @@ -1711,53 +1809,9 @@ private void authorizeNodeCollectionOperation(ModelAuthorizationAction action, C //region Workflow-related operations @Override - public int countWorkItemsRelatedToUser(String userOid, boolean assigned, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - return getWorkflowManagerChecked().countWorkItemsRelatedToUser(userOid, assigned, parentResult); - } - - @Override - public List listWorkItemsRelatedToUser(String userOid, boolean assigned, int first, int count, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - return getWorkflowManagerChecked().listWorkItemsRelatedToUser(userOid, assigned, first, count, parentResult); - } - - @Override - public WorkItemType getWorkItemDetailsById(String workItemId, OperationResult parentResult) throws ObjectNotFoundException { - return getWorkflowManagerChecked().getWorkItemDetailsById(workItemId, parentResult); - } - - @Override - public int countProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, OperationResult parentResult) { - return getWorkflowManagerChecked().countProcessInstancesRelatedToUser(userOid, requestedBy, requestedFor, finished, parentResult); - } - - @Override - public List listProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, int first, int count, OperationResult parentResult) { - return getWorkflowManagerChecked().listProcessInstancesRelatedToUser(userOid, requestedBy, requestedFor, finished, first, count, parentResult); - } - - @Override - public WfProcessInstanceType getProcessInstanceByWorkItemId(String workItemId, OperationResult parentResult) throws ObjectNotFoundException { - return getWorkflowManagerChecked().getProcessInstanceByWorkItemId(workItemId, parentResult); - } - - @Override - public WfProcessInstanceType getProcessInstanceById(String instanceId, boolean historic, boolean getWorkItems, OperationResult parentResult) throws ObjectNotFoundException { - return getWorkflowManagerChecked().getProcessInstanceById(instanceId, historic, getWorkItems, parentResult); - } - - @Override - public void approveOrRejectWorkItem(String workItemId, boolean decision, OperationResult parentResult) { - getWorkflowManagerChecked().approveOrRejectWorkItem(workItemId, decision, parentResult); - } - - @Override - public void approveOrRejectWorkItemWithDetails(String workItemId, PrismObject specific, boolean decision, OperationResult result) { - getWorkflowManagerChecked().approveOrRejectWorkItemWithDetails(workItemId, specific, decision, result); - } - - @Override - public void completeWorkItemWithDetails(String workItemId, PrismObject specific, String decision, OperationResult parentResult) { - getWorkflowManagerChecked().completeWorkItemWithDetails(workItemId, specific, decision, parentResult); + public void approveOrRejectWorkItem(String workItemId, boolean decision, String comment, OperationResult parentResult) + throws SecurityViolationException { + getWorkflowManagerChecked().approveOrRejectWorkItem(workItemId, decision, comment, parentResult); } @Override @@ -1771,12 +1825,12 @@ public void deleteProcessInstance(String instanceId, OperationResult parentResul } @Override - public void claimWorkItem(String workItemId, OperationResult parentResult) { + public void claimWorkItem(String workItemId, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException { getWorkflowManagerChecked().claimWorkItem(workItemId, parentResult); } @Override - public void releaseWorkItem(String workItemId, OperationResult parentResult) { + public void releaseWorkItem(String workItemId, OperationResult parentResult) throws ObjectNotFoundException, SecurityViolationException { getWorkflowManagerChecked().releaseWorkItem(workItemId, parentResult); } //endregion diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java index 739b0a1df67..24270cfcf5e 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/controller/ModelInteractionServiceImpl.java @@ -15,16 +15,16 @@ */ package com.evolveum.midpoint.model.impl.controller; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; +import java.util.*; import javax.xml.namespace.QName; +import com.evolveum.midpoint.model.api.*; +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.model.impl.visualizer.Visualizer; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.Validate; +import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -34,17 +34,11 @@ import com.evolveum.midpoint.common.refinery.LayerRefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; -import com.evolveum.midpoint.model.api.ModelAuthorizationAction; -import com.evolveum.midpoint.model.api.ModelExecuteOptions; -import com.evolveum.midpoint.model.api.ModelInteractionService; -import com.evolveum.midpoint.model.api.PolicyViolationException; -import com.evolveum.midpoint.model.api.RoleSelectionSpecification; import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.impl.ModelObjectResolver; import com.evolveum.midpoint.model.impl.lens.ContextFactory; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.lens.projector.Projector; -import com.evolveum.midpoint.prism.DisplayableValueImpl; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismObjectDefinition; @@ -127,7 +121,10 @@ public class ModelInteractionServiceImpl implements ModelInteractionService { @Autowired(required = true) private PrismContext prismContext; - + + @Autowired + private Visualizer visualizer; + /* (non-Javadoc) * @see com.evolveum.midpoint.model.api.ModelInteractionService#previewChanges(com.evolveum.midpoint.prism.delta.ObjectDelta, com.evolveum.midpoint.schema.result.OperationResult) */ @@ -135,7 +132,15 @@ public class ModelInteractionServiceImpl implements ModelInteractionService { public ModelContext previewChanges( Collection> deltas, ModelExecuteOptions options, Task task, OperationResult parentResult) throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { - + return previewChanges(deltas, options, task, Collections.emptyList(), parentResult); + } + + @Override + public ModelContext previewChanges( + Collection> deltas, ModelExecuteOptions options, Task task, + Collection listeners, OperationResult parentResult) + throws SchemaException, PolicyViolationException, ExpressionEvaluationException, ObjectNotFoundException, ObjectAlreadyExistsException, CommunicationException, ConfigurationException, SecurityViolationException { + if (LOGGER.isDebugEnabled()) { LOGGER.debug("Preview changes input:\n{}", DebugUtil.debugDump(deltas)); } @@ -161,7 +166,7 @@ public ModelContext previewChanges( if (LOGGER.isDebugEnabled()) { LOGGER.trace("Preview changes context:\n{}", context.debugDump()); } - + context.setProgressListeners(listeners); projector.projectAllWaves(context, "preview", task, result); context.distributeResource(); @@ -615,4 +620,15 @@ public boolean checkPassword(String userOid, ProtectedStringType password, Task return cmp; } + @Override + public List visualizeDeltas(List> deltas, Task task, OperationResult result) throws SchemaException { + return visualizer.visualizeDeltas(deltas, task, result); + } + + @Override + @NotNull + public Scene visualizeDelta(ObjectDelta delta, Task task, OperationResult result) throws SchemaException { + return visualizer.visualizeDelta(delta, task, result); + } + } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java index 1eb8525e450..53c74ad525c 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/Construction.java @@ -831,7 +831,7 @@ public String debugDump(int indent) { @Override public String toString() { return "Construction(" + (refinedObjectClassDefinition == null ? constructionType - : refinedObjectClassDefinition.getShadowDiscriminator()) + ")"; + : refinedObjectClassDefinition.getShadowDiscriminator()) + " in " + source + ")"; } } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java index 9f124c5bd78..ac301986284 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensContext.java @@ -602,6 +602,12 @@ public void recomputeProjections() throws SchemaException { projCtx.recompute(); } } + + public void refreshAuxiliaryObjectClassDefinitions() throws SchemaException { + for (LensProjectionContext projCtx: getProjectionContexts()) { + projCtx.refreshAuxiliaryObjectClassDefinitions(); + } + } public void checkAbortRequested() { if (isAbortRequested()) { diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensProjectionContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensProjectionContext.java index ed23cf89cc4..8bbb2e62ed6 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensProjectionContext.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/LensProjectionContext.java @@ -571,25 +571,30 @@ public RefinedObjectClassDefinition getStructuralObjectClassDefinition() throws public Collection getAuxiliaryObjectClassDefinitions() throws SchemaException { if (auxiliaryObjectClassDefinitions == null) { - RefinedResourceSchema refinedSchema = getRefinedResourceSchema(); - if (refinedSchema == null) { - return null; - } - List auxiliaryObjectClassQNames = new ArrayList<>(); - addAuxiliaryObjectClassNames(auxiliaryObjectClassQNames, getObjectOld()); - addAuxiliaryObjectClassNames(auxiliaryObjectClassQNames, getObjectNew()); - auxiliaryObjectClassDefinitions = new ArrayList<>(auxiliaryObjectClassQNames.size()); - for (QName auxiliaryObjectClassQName: auxiliaryObjectClassQNames) { - RefinedObjectClassDefinition auxiliaryObjectClassDef = refinedSchema.getRefinedDefinition(auxiliaryObjectClassQName); - if (auxiliaryObjectClassDef == null) { - throw new SchemaException("Auxiliary object class "+auxiliaryObjectClassQName+" specified in "+this+" does not exist"); - } - auxiliaryObjectClassDefinitions.add(auxiliaryObjectClassDef); - } + refreshAuxiliaryObjectClassDefinitions(); } return auxiliaryObjectClassDefinitions; } + public void refreshAuxiliaryObjectClassDefinitions() throws SchemaException { + RefinedResourceSchema refinedSchema = getRefinedResourceSchema(); + if (refinedSchema == null) { + return; + } + List auxiliaryObjectClassQNames = new ArrayList<>(); + addAuxiliaryObjectClassNames(auxiliaryObjectClassQNames, getObjectOld()); + addAuxiliaryObjectClassNames(auxiliaryObjectClassQNames, getObjectNew()); + auxiliaryObjectClassDefinitions = new ArrayList<>(auxiliaryObjectClassQNames.size()); + for (QName auxiliaryObjectClassQName: auxiliaryObjectClassQNames) { + RefinedObjectClassDefinition auxiliaryObjectClassDef = refinedSchema.getRefinedDefinition(auxiliaryObjectClassQName); + if (auxiliaryObjectClassDef == null) { + throw new SchemaException("Auxiliary object class "+auxiliaryObjectClassQName+" specified in "+this+" does not exist"); + } + auxiliaryObjectClassDefinitions.add(auxiliaryObjectClassDef); + } + compositeObjectClassDefinition = null; + } + public CompositeRefinedObjectClassDefinition getCompositeObjectClassDefinition() throws SchemaException { if (compositeObjectClassDefinition == null) { RefinedObjectClassDefinition structuralObjectClassDefinition = getStructuralObjectClassDefinition(); @@ -814,6 +819,7 @@ private void distributeResourceValues(Collection values, Pr * E.g. they may both be MODIFY deltas even in case that the account should be created. The deltas begin to make sense * only if combined with sync decision. This method provides the deltas all combined and ready for execution. */ + @Override public ObjectDelta getExecutableDelta() throws SchemaException { SynchronizationPolicyDecision policyDecision = getSynchronizationPolicyDecision(); ObjectDelta origDelta = getFixedDelta(); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ConsolidationProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ConsolidationProcessor.java index e19aa8f5e6f..727e89a3e1b 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ConsolidationProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ConsolidationProcessor.java @@ -18,8 +18,10 @@ import static com.evolveum.midpoint.common.InternalsConfig.consistencyChecks; +import com.evolveum.midpoint.common.refinery.CompositeRefinedObjectClassDefinition; import com.evolveum.midpoint.common.refinery.RefinedAssociationDefinition; import com.evolveum.midpoint.common.refinery.RefinedObjectClassDefinition; +import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition; import com.evolveum.midpoint.model.api.PolicyViolationException; import com.evolveum.midpoint.model.api.context.SynchronizationPolicyDecision; @@ -78,6 +80,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -229,12 +232,6 @@ public boolean isAuthoritative() { ResourceShadowDiscriminator discr = projCtx.getResourceShadowDiscriminator(); ObjectDelta objectDelta = new ObjectDelta(ShadowType.class, ChangeType.MODIFY, prismContext); objectDelta.setOid(projCtx.getOid()); - - RefinedObjectClassDefinition rOcDef = projCtx.getCompositeObjectClassDefinition(); - if (rOcDef == null) { - LOGGER.error("Definition for account type {} not found in the context, but it should be there, dumping context:\n{}", discr, context.debugDump()); - throw new IllegalStateException("Definition for account type " + discr + " not found in the context, but it should be there"); - } // Do not automatically load the full projection now. Even if we have weak mapping. // That may be a waste of resources if the weak mapping results in no change anyway. @@ -268,35 +265,14 @@ public boolean isAuthoritative() { boolean completeAccount = projCtx.hasFullShadow(); ObjectDelta existingDelta = projCtx.getDelta(); - - // ATTRIBUTES - // Iterate and process each attribute separately. Now that we have squeezed the data we can process each attribute just - // with the data in ItemValueWithOrigin triples. - for (Map.Entry,PrismPropertyDefinition>>> entry : squeezedAttributes.entrySet()) { - QName attributeName = entry.getKey(); - DeltaSetTriple,PrismPropertyDefinition>> triple = entry.getValue(); - PropertyDelta propDelta = consolidateAttribute(rOcDef, discr, existingDelta, projCtx, - addUnchangedValues, completeAccount, attributeName, (DeltaSetTriple)triple); - if (propDelta != null) { - objectDelta.addModification(propDelta); - } - } - - // ASSOCIATIONS - for (Entry,PrismContainerDefinition>>> entry : squeezedAssociations.entrySet()) { - QName associationName = entry.getKey(); - DeltaSetTriple,PrismContainerDefinition>> triple = entry.getValue(); - ContainerDelta containerDelta = consolidateAssociation(rOcDef, discr, existingDelta, projCtx, - addUnchangedValues, completeAccount, associationName, triple); - if (containerDelta != null) { - objectDelta.addModification(containerDelta); - } - } // AUXILIARY OBJECT CLASSES ItemPath auxiliaryObjectClassItemPath = new ItemPath(ShadowType.F_AUXILIARY_OBJECT_CLASS); PrismPropertyDefinition auxiliaryObjectClassPropertyDef = projCtx.getObjectDefinition().findPropertyDefinition(auxiliaryObjectClassItemPath); PropertyDelta auxiliaryObjectClassAPrioriDelta = null; + RefinedResourceSchema refinedSchema = projCtx.getRefinedResourceSchema(); + List auxOcNames = new ArrayList<>(); + List auxOcDefs = new ArrayList<>(); ObjectDelta projDelta = projCtx.getDelta(); if (projDelta != null) { auxiliaryObjectClassAPrioriDelta = projDelta.findPropertyDelta(auxiliaryObjectClassItemPath); @@ -304,12 +280,26 @@ public boolean isAuthoritative() { for (Entry, PrismPropertyDefinition>>> entry : squeezedAuxiliaryObjectClasses.entrySet()) { DeltaSetTriple, PrismPropertyDefinition>> ivwoTriple = entry.getValue(); - LOGGER.trace("CONSOLIDATE auxiliary object classes\n({})", - new Object[]{ discr }); + LOGGER.trace("CONSOLIDATE auxiliary object classes ({})", new Object[]{ discr }); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Auxiliary object class triple:\n{}",ivwoTriple.debugDump()); } + for (ItemValueWithOrigin,PrismPropertyDefinition> ivwo: ivwoTriple.getAllValues()) { + QName auxObjectClassName = ivwo.getItemValue().getValue(); + if (auxOcNames.contains(auxObjectClassName)) { + continue; + } + auxOcNames.add(auxObjectClassName); + RefinedObjectClassDefinition auxOcDef = refinedSchema.getRefinedDefinition(auxObjectClassName); + if (auxOcDef == null) { + LOGGER.error("Auxiliary object class definition {} for {} not found in the schema, but it should be there, dumping context:\n{}", + auxObjectClassName, discr, context.debugDump()); + throw new IllegalStateException("Auxiliary object class definition " + auxObjectClassName + " for "+ discr + " not found in the context, but it should be there"); + } + auxOcDefs.add(auxOcDef); + } + ItemDelta, PrismPropertyDefinition> itemDelta = LensUtil.consolidateTripleToDelta( auxiliaryObjectClassItemPath, ivwoTriple, auxiliaryObjectClassPropertyDef, auxiliaryObjectClassAPrioriDelta, projCtx.getObjectNew(), null, null, addUnchangedValues, completeAccount, false, @@ -324,6 +314,43 @@ public boolean isAuthoritative() { objectDelta.addModification(propDelta); } } + + RefinedObjectClassDefinition structuralObjectClassDefinition = projCtx.getStructuralObjectClassDefinition(); + if (structuralObjectClassDefinition == null) { + LOGGER.error("Structural object class definition for {} not found in the context, but it should be there, dumping context:\n{}", discr, context.debugDump()); + throw new IllegalStateException("Structural object class definition for " + discr + " not found in the context, but it should be there"); + } + + RefinedObjectClassDefinition rOcDef = new CompositeRefinedObjectClassDefinition( + structuralObjectClassDefinition, auxOcDefs); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Object class definition for {} consolidation:\n{}", discr, rOcDef.debugDump()); + } + + // ATTRIBUTES + // Iterate and process each attribute separately. Now that we have squeezed the data we can process each attribute just + // with the data in ItemValueWithOrigin triples. + for (Map.Entry,PrismPropertyDefinition>>> entry : squeezedAttributes.entrySet()) { + QName attributeName = entry.getKey(); + DeltaSetTriple,PrismPropertyDefinition>> triple = entry.getValue(); + PropertyDelta propDelta = consolidateAttribute(rOcDef, discr, existingDelta, projCtx, + addUnchangedValues, completeAccount, attributeName, (DeltaSetTriple)triple); + if (propDelta != null) { + objectDelta.addModification(propDelta); + } + } + + // ASSOCIATIONS + for (Entry,PrismContainerDefinition>>> entry : squeezedAssociations.entrySet()) { + QName associationName = entry.getKey(); + DeltaSetTriple,PrismContainerDefinition>> triple = entry.getValue(); + ContainerDelta containerDelta = consolidateAssociation(rOcDef, discr, existingDelta, projCtx, + addUnchangedValues, completeAccount, associationName, triple); + if (containerDelta != null) { + objectDelta.addModification(containerDelta); + } + } return objectDelta; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/OutboundProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/OutboundProcessor.java index 4ec65df2c19..9ede514ab14 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/OutboundProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/OutboundProcessor.java @@ -104,7 +104,7 @@ public void processOutbound(LensContext context, LensPr LOGGER.trace("Processing outbound expressions for {} starting", discr); - RefinedObjectClassDefinition rOcDef = projCtx.getCompositeObjectClassDefinition(); + RefinedObjectClassDefinition rOcDef = projCtx.getStructuralObjectClassDefinition(); if (rOcDef == null) { LOGGER.error("Definition for {} not found in the context, but it should be there, dumping context:\n{}", discr, context.debugDump()); throw new IllegalStateException("Definition for " + discr + " not found in the context, but it should be there"); diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ProjectionValuesProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ProjectionValuesProcessor.java index a71da90064b..ffa721525de 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ProjectionValuesProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/ProjectionValuesProcessor.java @@ -233,6 +233,9 @@ private void processProjections(LensContext context, context.recompute(); if (consistencyChecks) context.checkConsistence(); + // Aux object classes may have changed during consolidation. Make sure we have up-to-date definitions. + context.refreshAuxiliaryObjectClassDefinitions(); + // Check if we need to reset the iteration counter (and token) e.g. because we have rename // we cannot do that before because the mappings are not yet evaluated and the triples and not // consolidated to deltas. We can do it only now. It means that we will waste the first run diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/Resolver.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/Resolver.java new file mode 100644 index 00000000000..c01f335a569 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/Resolver.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.visualizer; + +import com.evolveum.midpoint.model.api.ModelService; +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.provisioning.api.ProvisioningService; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.util.logging.LoggingUtils; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +import static com.evolveum.midpoint.schema.GetOperationOptions.createNoFetch; +import static com.evolveum.midpoint.schema.SelectorOptions.createCollection; +import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.*; + +/** + * Resolves definitions and old values. + * Currently NOT references. + * + * @author mederly + */ +@Component +public class Resolver { + + private static final Trace LOGGER = TraceManager.getTrace(Resolver.class); + + public static final String CLASS_DOT = Resolver.class.getName() + "."; + private static final String OP_RESOLVE = CLASS_DOT + "resolve"; + + @Autowired + private PrismContext prismContext; + + @Autowired + private ModelService modelService; + + @Autowired + private ProvisioningService provisioningService; + + @Autowired + private Visualizer visualizer; + + public void resolve(PrismObject object, Task task, OperationResult result) throws SchemaException { + /*if (object.getDefinition() == null) */{ + Class clazz = object.getCompileTimeClass(); + if (clazz == null) { + warn(result, "Compile time class for " + toShortString(object) + " is not known"); + } else { + PrismObjectDefinition def = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(clazz); + if (def != null) { + if (ResourceType.class.isAssignableFrom(clazz) || ShadowType.class.isAssignableFrom(clazz)) { + try { + provisioningService.applyDefinition(object, result); + } catch (ObjectNotFoundException|CommunicationException|ConfigurationException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't apply definition on {} -- continuing with no definition", e, + ObjectTypeUtil.toShortString(object)); + } + } else { + object.applyDefinition(def); + } + } else { + warn(result, "Definition for " + toShortString(object) + " couldn't be found"); + } + } + } + } + + public void resolve(ObjectDelta objectDelta, Task task, OperationResult result) throws SchemaException { + if (objectDelta.isAdd()) { + resolve(objectDelta.getObjectToAdd(), task, result); + } else if (objectDelta.isDelete()) { + // nothing to do + } else { + PrismObject originalObject = null; + boolean originalObjectFetched = false; + final Class clazz = objectDelta.getObjectTypeClass(); + PrismObjectDefinition objectDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(clazz); + if (objectDefinition == null) { + warn(result, "Definition for " + clazz + " couldn't be found"); + } else { + if (ResourceType.class.isAssignableFrom(clazz) || ShadowType.class.isAssignableFrom(clazz)) { + try { + provisioningService.applyDefinition(objectDelta, result); + } catch (ObjectNotFoundException | CommunicationException | ConfigurationException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't apply definition on {} -- continuing with no definition", e, objectDelta); + } + } + } + for (ItemDelta itemDelta : objectDelta.getModifications()) { + if (objectDefinition != null) { + ItemDefinition def = objectDefinition.findItemDefinition(itemDelta.getPath()); + if (def != null) { + itemDelta.applyDefinition(def); + } + } + if (itemDelta.getEstimatedOldValues() == null) { + if (!originalObjectFetched) { + final String oid = objectDelta.getOid(); + try { + originalObject = modelService.getObject(clazz, oid, createCollection(createNoFetch()), task, result); + } catch (RuntimeException|SchemaException|ConfigurationException |CommunicationException |SecurityViolationException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't resolve object {}", e, oid); + warn(result, "Couldn't resolve object " + oid + ": " + e.getMessage(), e); + } catch (ObjectNotFoundException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't resolve object {}", e, oid); + warn(result, "Couldn't resolve object " + oid + ": " + e.getMessage(), e); + } + originalObjectFetched = true; + } + if (originalObject != null) { + Item originalItem = originalObject.findItem(itemDelta.getPath()); + if (originalItem != null) { + itemDelta.setEstimatedOldValues(new ArrayList(originalItem.getValues())); + } + } + } + } + } + } + + private void warn(OperationResult result, String text, Exception e) { + result.createSubresult(OP_RESOLVE).recordWarning(text, e); + } + + private void warn(OperationResult result, String text) { + result.createSubresult(OP_RESOLVE).recordWarning(text); + } + + // TODO caching retrieved objects + public void resolve(List> deltas, Task task, OperationResult result) throws SchemaException { + for (ObjectDelta delta : deltas) { + resolve(delta, task, result); + } + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/VisualizationContext.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/VisualizationContext.java new file mode 100644 index 00000000000..fb6c533667d --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/VisualizationContext.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.visualizer; + +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author mederly + */ +public class VisualizationContext { + + private boolean separateSinglevaluedContainers = true; + private boolean separateMultivaluedContainers = true; + private boolean separateSinglevaluedContainersInDeltas = true; + private boolean separateMultivaluedContainersInDeltas = true; + private boolean removeExtraDescriptiveItems = true; + private boolean includeOperationalItems = false; + private Map> oldObjects; + private Map> currentObjects; + + public boolean isSeparateSinglevaluedContainers() { + return separateSinglevaluedContainers; + } + + public void setSeparateSinglevaluedContainers(boolean separateSinglevaluedContainers) { + this.separateSinglevaluedContainers = separateSinglevaluedContainers; + } + + public boolean isSeparateMultivaluedContainers() { + return separateMultivaluedContainers; + } + + public void setSeparateMultivaluedContainers(boolean separateMultivaluedContainers) { + this.separateMultivaluedContainers = separateMultivaluedContainers; + } + + public boolean isSeparateSinglevaluedContainersInDeltas() { + return separateSinglevaluedContainersInDeltas; + } + + public void setSeparateSinglevaluedContainersInDeltas(boolean separateSinglevaluedContainersInDeltas) { + this.separateSinglevaluedContainersInDeltas = separateSinglevaluedContainersInDeltas; + } + + public boolean isSeparateMultivaluedContainersInDeltas() { + return separateMultivaluedContainersInDeltas; + } + + public void setSeparateMultivaluedContainersInDeltas(boolean separateMultivaluedContainersInDeltas) { + this.separateMultivaluedContainersInDeltas = separateMultivaluedContainersInDeltas; + } + + public boolean isRemoveExtraDescriptiveItems() { + return removeExtraDescriptiveItems; + } + + public void setRemoveExtraDescriptiveItems(boolean removeExtraDescriptiveItems) { + this.removeExtraDescriptiveItems = removeExtraDescriptiveItems; + } + + public boolean isIncludeOperationalItems() { + return includeOperationalItems; + } + + public void setIncludeOperationalItems(boolean includeOperationalItems) { + this.includeOperationalItems = includeOperationalItems; + } + + public Map> getOldObjects() { + if (oldObjects == null) { + oldObjects = new HashMap<>(); + } + return oldObjects; + } + + public void setOldObjects(Map> oldObjects) { + this.oldObjects = oldObjects; + } + + public PrismObject getOldObject(String oid) { + return getOldObjects().get(oid); + } + + public Map> getCurrentObjects() { + if (currentObjects == null) { + currentObjects = new HashMap<>(); + } + return currentObjects; + } + + public void setCurrentObjects( + Map> currentObjects) { + this.currentObjects = currentObjects; + } + + public PrismObject getCurrentObject(String oid) { + return getCurrentObjects().get(oid); + } + + public void putObject(PrismObject object) { + getCurrentObjects().put(object.getOid(), object); + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/Visualizer.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/Visualizer.java new file mode 100644 index 00000000000..75f4e16f7f4 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/Visualizer.java @@ -0,0 +1,836 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.visualizer; + +import com.evolveum.midpoint.model.api.ModelService; +import com.evolveum.midpoint.model.impl.visualizer.output.*; +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.*; +import com.evolveum.midpoint.prism.path.IdItemPathSegment; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.util.CloneUtil; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ValueDisplayUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.util.logging.LoggingUtils; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +import static com.evolveum.midpoint.prism.delta.ChangeType.*; +import static com.evolveum.midpoint.prism.path.ItemPath.EMPTY_PATH; +import static com.evolveum.midpoint.prism.path.ItemPath.isNullOrEmpty; +import static com.evolveum.midpoint.prism.polystring.PolyString.getOrig; +import static com.evolveum.midpoint.schema.GetOperationOptions.createNoFetch; +import static com.evolveum.midpoint.schema.SelectorOptions.createCollection; + +/** + * @author mederly + */ + +@Component +public class Visualizer { + + private static final Trace LOGGER = TraceManager.getTrace(Visualizer.class); + public static final String CLASS_DOT = Visualizer.class.getName() + "."; + + @Autowired + private PrismContext prismContext; + + @Autowired + private ModelService modelService; + + @Autowired + private Resolver resolver; + + private static final Map, List> descriptiveItems = new HashMap<>(); + static { + descriptiveItems.put(AssignmentType.class, Arrays.asList( + new ItemPath(AssignmentType.F_TARGET_REF), + new ItemPath(AssignmentType.F_CONSTRUCTION, ConstructionType.F_RESOURCE_REF), + new ItemPath(AssignmentType.F_CONSTRUCTION, ConstructionType.F_KIND), + new ItemPath(AssignmentType.F_CONSTRUCTION, ConstructionType.F_INTENT), + new ItemPath(AssignmentType.F_TENANT_REF), + new ItemPath(AssignmentType.F_ORG_REF), + new ItemPath(AssignmentType.F_DESCRIPTION))); + descriptiveItems.put(ShadowType.class, Arrays.asList( + new ItemPath(ShadowType.F_RESOURCE_REF), + new ItemPath(ShadowType.F_KIND), + new ItemPath(ShadowType.F_INTENT))); + } + + public SceneImpl visualize(PrismObject object, Task task, OperationResult parentResult) throws SchemaException { + return visualize(object, new VisualizationContext(), task, parentResult); + } + + public SceneImpl visualize(PrismObject object, VisualizationContext context, Task task, OperationResult parentResult) + throws SchemaException { + OperationResult result = parentResult.createSubresult(CLASS_DOT + "visualize"); + try { + resolver.resolve(object, task, result); + return visualize(object, null, context, task, result); + } catch (RuntimeException|SchemaException e) { + result.recordFatalError("Couldn't visualize data structure: " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); + } + } + + private SceneImpl visualize(PrismObject object, SceneImpl owner, VisualizationContext context, Task task, OperationResult result) { + SceneImpl scene = new SceneImpl(owner); + scene.setChangeType(null); + scene.setName(createSceneName(object)); + scene.setSourceRelPath(EMPTY_PATH); + scene.setSourceAbsPath(EMPTY_PATH); + scene.setSourceDefinition(object.getDefinition()); + scene.setSourceValue(object.getValue()); + scene.setSourceDelta(null); + visualizeItems(scene, object.getValue().getItems(), false, context, task, result); + return scene; + } + + @SuppressWarnings("unused") + private SceneImpl visualize(PrismContainerValue containerValue, SceneImpl owner, VisualizationContext context, Task task, OperationResult result) { + SceneImpl scene = new SceneImpl(owner); + scene.setChangeType(null); + NameImpl name = new NameImpl("id " + containerValue.getId()); // TODO + scene.setName(name); + scene.setSourceRelPath(EMPTY_PATH); + scene.setSourceAbsPath(EMPTY_PATH); + if (containerValue.getConcreteTypeDefinition() != null) { + scene.setSourceDefinition(containerValue.getConcreteTypeDefinition()); + } else if (containerValue.getParent() != null && containerValue.getParent().getDefinition() != null) { + scene.setSourceDefinition(containerValue.getParent().getDefinition()); + } + scene.setSourceValue(containerValue); + scene.setSourceDelta(null); + visualizeItems(scene, containerValue.getItems(), false, context, task, result); + return scene; + } + + public List visualizeDeltas(List> deltas, Task task, OperationResult parentResult) throws SchemaException { + OperationResult result = parentResult.createSubresult(CLASS_DOT + "visualizeDeltas"); + try { + resolver.resolve(deltas, task, result); + return visualizeDeltas(deltas, new VisualizationContext(), task, result); + } catch (RuntimeException|SchemaException e) { + result.recordFatalError("Couldn't visualize the data structure: " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); + } + } + + private List visualizeDeltas(List> deltas, VisualizationContext context, Task task, OperationResult result) + throws SchemaException { + List rv = new ArrayList<>(deltas.size()); + for (ObjectDelta delta : deltas) { + rv.add(visualizeDelta(delta, null, context, task, result)); + } + return rv; + } + + @NotNull + public SceneImpl visualizeDelta(ObjectDelta objectDelta, Task task, OperationResult parentResult) throws SchemaException { + OperationResult result = parentResult.createSubresult(CLASS_DOT + "visualizeDelta"); + try { + resolver.resolve(objectDelta, task, result); + return visualizeDelta(objectDelta, null, new VisualizationContext(), task, result); + } catch (RuntimeException|SchemaException e) { + result.recordFatalError("Couldn't visualize the data structure: " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); + } + } + + private SceneImpl visualizeDelta(ObjectDelta objectDelta, SceneImpl owner, VisualizationContext context, Task task, OperationResult result) + throws SchemaException { + SceneImpl scene = new SceneImpl(owner); + scene.setChangeType(objectDelta.getChangeType()); + scene.setSourceDelta(objectDelta); + scene.setSourceRelPath(ItemPath.EMPTY_PATH); + scene.setSourceAbsPath(ItemPath.EMPTY_PATH); + PrismObject object = + objectDelta.isAdd() ? objectDelta.getObjectToAdd() : getOldObject(objectDelta.getOid(), objectDelta.getObjectTypeClass(), context, task, result); + if (object != null) { + scene.setName(createSceneName(object)); + scene.setSourceValue(object.getValue()); + scene.setSourceDefinition(object.getDefinition()); + } else { + scene.setName(createSceneName(objectDelta.getOid())); + } + if (objectDelta.isAdd()) { + if (object == null) { + throw new IllegalStateException("ADD object delta with no object to add: " + objectDelta); + } + visualizeItems(scene, object.getValue().getItems(), false, context, task, result); + } else if (objectDelta.isModify()) { + if (object != null) { + addDescriptiveItems(scene, object.getValue(), context, task, result); + } + visualizeItemDeltas(scene, objectDelta.getModifications(), context, task, result); + } else if (objectDelta.isDelete()) { + if (object != null) { + addDescriptiveItems(scene, object.getValue(), context, task, result); + } + } else { + throw new IllegalStateException("Object delta that is neither ADD, nor MODIFY nor DELETE: " + objectDelta); + } + return scene; + } + + private PrismObject getOldObject(String oid, Class objectTypeClass, VisualizationContext context, Task task, OperationResult result) { + PrismObject object = context.getOldObject(oid); + if (object != null) { + return object; + } + return getObject(oid, objectTypeClass, context, task, result); + } + + private PrismObject getObject(String oid, Class objectTypeClass, VisualizationContext context, Task task, OperationResult result) { + PrismObject object = context.getCurrentObject(oid); + if (object != null) { + return object; + } + try { + object = modelService.getObject(objectTypeClass, oid, createCollection(createNoFetch()), task, result); + context.putObject(object); + return object; + } catch (RuntimeException|SchemaException|ConfigurationException|CommunicationException|SecurityViolationException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't resolve object {}", e, oid); + result.recordWarning("Couldn't resolve object " + oid + ": " + e.getMessage(), e); + return null; + } catch (ObjectNotFoundException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't resolve object {}", e, oid); + result.recordWarning("Couldn't resolve object " + oid + ": " + e.getMessage(), e); + return null; + } + } + + private void visualizeItems(SceneImpl scene, List> items, boolean descriptive, VisualizationContext context, Task task, OperationResult result) { + if (items == null) { + return; + } + List> itemsToShow = new ArrayList<>(items); + Collections.sort(itemsToShow, getItemDisplayOrderComparator()); + for (Item item : itemsToShow) { + if (item instanceof PrismProperty) { + final SceneItemImpl sceneItem = createSceneItem((PrismProperty) item, descriptive); + if (!sceneItem.isOperational() || context.isIncludeOperationalItems()) { + scene.addItem(sceneItem); + } + } else if (item instanceof PrismReference) { + final SceneItemImpl sceneItem = createSceneItem((PrismReference) item, descriptive, context, task, result); + if (!sceneItem.isOperational() || context.isIncludeOperationalItems()) { + scene.addItem(sceneItem); + } + } else if (item instanceof PrismContainer) { + PrismContainer pc = (PrismContainer) item; + PrismContainerDefinition def = pc.getDefinition(); + boolean separate = isContainerSingleValued(def, pc) ? context.isSeparateSinglevaluedContainers() : context.isSeparateMultivaluedContainers(); + SceneImpl currentScene = scene; + for (PrismContainerValue pcv : pc.getValues()) { + if (separate) { + SceneImpl si = new SceneImpl(scene); + NameImpl name = new NameImpl(item.getElementName().getLocalPart()); + name.setId(name.getSimpleName()); + if (def != null) { + name.setDisplayName(def.getDisplayName()); + } + si.setName(name); + if (def != null) { + si.setOperational(def.isOperational()); + si.setSourceDefinition(def); + if (si.isOperational() && !context.isIncludeOperationalItems()) { + continue; + } + } + si.setSourceRelPath(new ItemPath(item.getElementName())); + si.setSourceAbsPath(scene.getSourceAbsPath().subPath(item.getElementName())); + si.setSourceDelta(null); + scene.addPartialScene(si); + currentScene = si; + } + visualizeItems(currentScene, pcv.getItems(), descriptive, context, task, result); + } + } else { + throw new IllegalStateException("Not a property nor reference nor container: " + item); + } + } + } + + private boolean isContainerSingleValued(PrismContainerDefinition def, PrismContainer pc) { + if (def == null) { + return pc.getValues().size() <= 1; + } else { + return def.isSingleValue(); + } + } + + private void visualizeItemDeltas(SceneImpl scene, Collection> deltas, VisualizationContext context, Task task, + OperationResult result) throws SchemaException { + if (deltas == null) { + return; + } + List> deltasToShow = new ArrayList<>(deltas); + for (ItemDelta delta : deltasToShow) { + if (delta instanceof ContainerDelta) { + visualizeContainerDelta((ContainerDelta) delta, scene, context, task, result); + } else { + visualizeAtomicDelta(delta, scene, context, task, result); + } + } + sortItems(scene); + sortPartialScenes(scene); + } + + private void sortItems(SceneImpl scene) { + Collections.sort(scene.getItems(), new Comparator() { + @Override + public int compare(SceneItemImpl o1, SceneItemImpl o2) { + return compareDefinitions(o1.getSourceDefinition(), o2.getSourceDefinition()); + } + }); + } + + private void sortPartialScenes(SceneImpl scene) { + Collections.sort(scene.getPartialScenes(), new Comparator() { + @Override + public int compare(SceneImpl s1, SceneImpl s2) { + final PrismContainerDefinition def1 = s1.getSourceDefinition(); + final PrismContainerDefinition def2 = s2.getSourceDefinition(); + int a = compareDefinitions(def1, def2); + if (a != 0) { + return a; + } + if (def1 == null && def2 == null) { + return 0; + } else if (def1 == null) { + return 1; + } else if (def2 == null) { + return -1; + } + if (s1.isContainerValue() && s2.isContainerValue()) { + Long id1 = s1.getSourceContainerValueId(); + Long id2 = s2.getSourceContainerValueId(); + return compareNullableIntegers(id1, id2); + } else if (s1.isObjectValue() && s2.isObjectValue()) { + boolean f1 = s1.isFocusObject(); + boolean f2 = s2.isFocusObject(); + if (f1 && !f2) { + return -1; + } else if (f2 && !f1) { + return 1; + } else { + return 0; + } + } + if (s1.isObjectValue()) { + return -1; + } else if (s2.isObjectValue()) { + return 1; + } + return 0; + } + }); + } + + private void visualizeContainerDelta(ContainerDelta delta, SceneImpl scene, VisualizationContext context, Task task, OperationResult result) { + if (delta.isEmpty()) { + return; + } + if (delta.getDefinition() != null && delta.getDefinition().isOperational() && !context.isIncludeOperationalItems()) { + return; + } + Collection> valuesToAdd; + Collection> valuesToDelete; + if (!delta.isReplace()) { + valuesToAdd = delta.getValuesToAdd(); + valuesToDelete = delta.getValuesToDelete(); + } else { + valuesToAdd = new ArrayList<>(); + valuesToDelete = new ArrayList<>(); + Collection> oldValues = delta.getEstimatedOldValues(); + for (PrismContainerValue newValue : delta.getValuesToReplace()) { + if (oldValues == null || !oldValues.contains(newValue)) { // TODO containsEquivalentValue instead? + valuesToAdd.add(newValue); + } + } + if (oldValues != null) { + for (PrismContainerValue oldValue : oldValues) { + if (!delta.getValuesToReplace().contains(oldValue)) { // TODO containsEquivalentValue instead? + valuesToDelete.add(oldValue); + } + } + } + } + if (valuesToDelete != null) { + for (PrismContainerValue value : valuesToDelete) { + visualizeContainerDeltaValue(value, DELETE, delta, scene, context, task, result); + } + } + if (valuesToAdd != null) { + for (PrismContainerValue value : valuesToAdd) { + visualizeContainerDeltaValue(value, ADD, delta, scene, context, task, result); + } + } + } + + private void visualizeContainerDeltaValue(PrismContainerValue value, ChangeType changeType, + ContainerDelta containerDelta, SceneImpl owningScene, VisualizationContext context, Task task, OperationResult result) { + SceneImpl scene = createContainerScene(changeType, containerDelta.getPath(), owningScene); + if (value.getId() != null) { + scene.getName().setId(String.valueOf(value.getId())); + } + // delete-by-id: we supply known values + if ((value.getItems() == null || value.getItems().isEmpty()) && value.getId() != null) { + if (containerDelta.getEstimatedOldValues() != null) { + for (PrismContainerValue oldValue : containerDelta.getEstimatedOldValues()) { + if (value.getId().equals(oldValue.getId())) { + value = oldValue; + break; + } + } + } + } + scene.setSourceValue(value); + visualizeItems(scene, value.getItems(), false, context, task, result); + + owningScene.addPartialScene(scene); + } + + private SceneImpl createContainerScene(ChangeType changeType, ItemPath containerPath, SceneImpl owningScene) { + SceneImpl scene = new SceneImpl(owningScene); + scene.setChangeType(changeType); + + ItemPath deltaParentItemPath = getDeltaParentItemPath(containerPath); + PrismContainerDefinition sceneDefinition = getSceneDefinition(scene, deltaParentItemPath); + + NameImpl name = createNameForContainerDelta(containerPath, sceneDefinition); + scene.setName(name); + + if (sceneDefinition != null) { + scene.setOperational(sceneDefinition.isOperational()); + scene.setSourceDefinition(sceneDefinition); + } + + ItemPath sceneRelativePath = containerPath.remainder(owningScene.getSourceRelPath()); + scene.setSourceRelPath(sceneRelativePath); + scene.setSourceAbsPath(containerPath); + scene.setSourceDelta(null); + return scene; + } + + private NameImpl createNameForContainerDelta(ItemPath deltaParentPath, PrismContainerDefinition sceneDefinition) { + NameImpl name = new NameImpl(deltaParentPath.toString()); + name.setId(String.valueOf(getLastId(deltaParentPath))); + if (sceneDefinition != null) { + name.setDisplayName(sceneDefinition.getDisplayName()); + } + return name; + } + + private ItemPath getDeltaParentItemPath(ItemPath deltaParentPath) { + if (deltaParentPath.last() instanceof IdItemPathSegment) { + return deltaParentPath.allExceptLast(); + } else { + return deltaParentPath; + } + } + + private Long getLastId(ItemPath deltaParentPath) { + if (deltaParentPath.last() instanceof IdItemPathSegment) { + return ((IdItemPathSegment) deltaParentPath.last()).getId(); + } else { + return null; + } + } + + private PrismContainerDefinition getSceneDefinition(SceneImpl ownerScene, ItemPath deltaParentItemPath) { + PrismContainerDefinition rootDefinition = getRootDefinition(ownerScene); + if (rootDefinition == null) { + return null; + } else { + return rootDefinition.findContainerDefinition(deltaParentItemPath); + } + } + + private void visualizeAtomicDelta(ItemDelta delta, SceneImpl scene, VisualizationContext context, Task task, OperationResult result) + throws SchemaException { + ItemPath deltaParentPath = delta.getParentPath(); + ItemPath sceneRelativeItemPath = getDeltaParentItemPath(deltaParentPath).remainder(scene.getSourceRelPath()); + SceneImpl sceneForItem; + if (isNullOrEmpty(deltaParentPath)) { + sceneForItem = scene; + } else { + sceneForItem = findPartialSceneByPath(scene, deltaParentPath); + if (sceneForItem == null) { + sceneForItem = createContainerScene(MODIFY, deltaParentPath, scene); + if (sceneForItem.isOperational() && !context.isIncludeOperationalItems()) { + return; + } + PrismContainerValue ownerPCV = scene.getSourceValue(); + if (ownerPCV != null) { + Item item = ownerPCV.findItem(sceneRelativeItemPath); + if (item instanceof PrismContainer) { + PrismContainer container = (PrismContainer) item; + sceneForItem.setSourceDefinition(container.getDefinition()); + Long lastId = getLastId(deltaParentPath); + PrismContainerValue sceneSrcValue; + if (lastId == null) { + if (container.size() == 1) { + sceneSrcValue = container.getValues().get(0); + } else { + sceneSrcValue = null; + } + } else { + sceneSrcValue = container.findValue(lastId); + } + if (sceneSrcValue != null) { + sceneForItem.setSourceValue(sceneSrcValue); + addDescriptiveItems(sceneForItem, sceneSrcValue, context, task, result); + } + } + } + scene.addPartialScene(sceneForItem); + } + } + ItemPath itemRelativeItemPath = getDeltaParentItemPath(delta.getPath()).remainder(sceneForItem.getSourceRelPath()); + if (context.isRemoveExtraDescriptiveItems()) { + Iterator iterator = sceneForItem.getItems().iterator(); + while (iterator.hasNext()) { + SceneItemImpl sceneItem = iterator.next(); + if (sceneItem.isDescriptive() && sceneItem.getSourceRelPath() != null && sceneItem.getSourceRelPath().equivalent(itemRelativeItemPath)) { + iterator.remove(); + break; + } + } + } + visualizeAtomicItemDelta(sceneForItem, delta, context, task, result); + } + + private void addDescriptiveItems(SceneImpl scene, PrismContainerValue sourceValue, VisualizationContext context, Task task, OperationResult result) { + // TODO dynamically typed values + if (sourceValue.getContainer() == null || sourceValue.getContainer().getCompileTimeClass() == null) { + return; + } + Class clazz = sourceValue.getContainer().getCompileTimeClass(); + List itemPathsToShow = descriptiveItems.get(clazz); + if (itemPathsToShow == null) { + return; + } + List> itemsToShow = new ArrayList<>(); + for (ItemPath itemPath : itemPathsToShow) { + Item item = sourceValue.findItem(itemPath); + if (item != null) { + itemsToShow.add(item); + } + } + visualizeItems(scene, itemsToShow, true, context, task, result); + } + + private PrismContainerDefinition getRootDefinition(SceneImpl scene) { + while (scene.getOwner() != null) { + scene = scene.getOwner(); + } + return scene.getSourceDefinition(); + } + + private SceneImpl findPartialSceneByPath(SceneImpl scene, ItemPath deltaParentPath) { + for (SceneImpl subscene : scene.getPartialScenes()) { + if (subscene.getSourceAbsPath().equivalent(deltaParentPath) && subscene.getChangeType() == MODIFY) { + return subscene; + } + } + return null; + } + + private void visualizeAtomicItemDelta(SceneImpl scene, ItemDelta delta, VisualizationContext context, Task task, OperationResult result) + throws SchemaException { + final SceneDeltaItemImpl sceneDeltaItem; + if (delta instanceof PropertyDelta) { + sceneDeltaItem = createSceneDeltaItem((PropertyDelta) delta, scene, context, task, result); + } else if (delta instanceof ReferenceDelta) { + sceneDeltaItem = createSceneDeltaItem((ReferenceDelta) delta, scene, context, task, result); + } else { + throw new IllegalStateException("No property nor reference delta: " + delta); + } + if (!sceneDeltaItem.isOperational() || context.isIncludeOperationalItems()) { + scene.addItem(sceneDeltaItem); + } + } + + private Comparator> getItemDisplayOrderComparator() { + return new Comparator>() { + @Override + public int compare(Item o1, Item o2) { + return compareDefinitions(o1.getDefinition(), o2.getDefinition()); + } + }; + } + + private int compareDefinitions(ItemDefinition d1, ItemDefinition d2) { + Integer order1 = d1 != null ? d1.getDisplayOrder() : null; + Integer order2 = d2 != null ? d2.getDisplayOrder() : null; + return compareNullableIntegers(order1, order2); + } + + private int compareNullableIntegers(Integer i1, Integer i2) { + if (i1 == null && i2 == null) { + return 0; + } else if (i1 == null) { + return 1; + } else if (i2 == null) { + return -1; + } else { + return Integer.compare(i1, i2); + } + } + + private int compareNullableIntegers(Long i1, Long i2) { + if (i1 == null && i2 == null) { + return 0; + } else if (i1 == null) { + return 1; + } else if (i2 == null) { + return -1; + } else { + return Long.compare(i1, i2); + } + } + + private SceneItemImpl createSceneItemCommon(Item item) { + SceneItemImpl si = new SceneItemImpl(createSceneItemName(item)); + ItemDefinition def = item.getDefinition(); + if (def != null) { + si.setOperational(def.isOperational()); + } + si.setSourceItem(item); + si.setSourceRelPath(new ItemPath(item.getElementName())); + return si; + } + + private SceneItemImpl createSceneItem(PrismProperty property, boolean descriptive) { + SceneItemImpl si = createSceneItemCommon(property); + si.setNewValues(toSceneItemValues(property.getValues())); + si.setDescriptive(descriptive); + return si; + } + + private SceneItemImpl createSceneItem(PrismReference reference, boolean descriptive, VisualizationContext context, Task task, + OperationResult result) { + SceneItemImpl si = createSceneItemCommon(reference); + si.setNewValues(toSceneItemValuesRef(reference.getValues(), context, task, result)); + si.setDescriptive(descriptive); + return si; + } + + @SuppressWarnings({ "unused", "unchecked" }) + private SceneDeltaItemImpl createSceneDeltaItem(PropertyDelta delta, SceneImpl owningScene, VisualizationContext context, Task task, + OperationResult result) throws SchemaException { + SceneDeltaItemImpl si = createSceneDeltaItemCommon(delta, owningScene); + si.setOldValues(toSceneItemValues(delta.getEstimatedOldValues())); + + PrismProperty property = new PrismProperty(delta.getElementName(), prismContext); + if (delta.getEstimatedOldValues() != null) { + property.addValues(CloneUtil.cloneCollectionMembers(delta.getEstimatedOldValues())); + } + try { + delta.applyToMatchingPath(property); + } catch (SchemaException e) { + throw new SystemException("Couldn't visualize property delta: " + delta + ": " + e.getMessage(), e); + } + computeAddedDeletedUnchanged(si, delta.getEstimatedOldValues(), property.getValues()); + si.setNewValues(toSceneItemValues(property.getValues())); + return si; + } + + private > void computeAddedDeletedUnchanged(SceneDeltaItemImpl si, Collection oldValues, Collection newValues) { + List added = new ArrayList<>(); + List deleted = new ArrayList<>(); + List unchanged = new ArrayList<>(); + computeDifferences(oldValues, newValues, added, deleted, unchanged); + si.setAddedValues(toSceneItemValues(added)); + si.setDeletedValues(toSceneItemValues(deleted)); + si.setUnchangedValues(toSceneItemValues(unchanged)); + } + + private void computeDifferences(Collection oldValues, Collection newValues, List added, List deleted, List unchanged) { + if (oldValues != null) { + for (V oldValue : oldValues) { + if (newValues != null && newValues.contains(oldValue)) { + unchanged.add(oldValue); + } else { + deleted.add(oldValue); + } + } + } + if (newValues != null) { + for (V newValue : newValues) { + if (oldValues == null || !oldValues.contains(newValue)) { + added.add(newValue); + } + } + } + } + + private void computeAddedDeletedUnchangedRef(SceneDeltaItemImpl si, Collection oldValues, Collection newValues, + VisualizationContext context, Task task, OperationResult result) { + List added = new ArrayList<>(); + List deleted = new ArrayList<>(); + List unchanged = new ArrayList<>(); + computeDifferences(oldValues, newValues, added, deleted, unchanged); + si.setAddedValues(toSceneItemValuesRef(added, context, task, result)); + si.setDeletedValues(toSceneItemValuesRef(deleted, context, task, result)); + si.setUnchangedValues(toSceneItemValuesRef(unchanged, context, task, result)); + } + + @SuppressWarnings("unchecked") + private SceneDeltaItemImpl createSceneDeltaItemCommon(ItemDelta itemDelta, + SceneImpl owningScene) + throws SchemaException { + String simpleName = itemDelta.getElementName() != null ? itemDelta.getElementName().getLocalPart() : ""; + NameImpl name = new NameImpl(simpleName); + if (itemDelta.getDefinition() != null) { + name.setDisplayName(itemDelta.getDefinition().getDisplayName()); + } + name.setId(simpleName); + + SceneDeltaItemImpl si = new SceneDeltaItemImpl(name); + si.setSourceDelta(itemDelta); + + D def = itemDelta.getDefinition(); + if (def != null) { + Item item = def.instantiate(); + if (itemDelta.getEstimatedOldValues() != null) { + item.addAll(CloneUtil.cloneCollectionMembers(itemDelta.getEstimatedOldValues())); + } + si.setSourceItem(item); + si.setOperational(def.isOperational()); + } + ItemPath remainder = itemDelta.getPath().remainder(owningScene.getSourceRelPath()); + if (remainder.startsWith(new ItemPath(new IdItemPathSegment()))) { + remainder = remainder.tail(); + } + si.setSourceRelPath(remainder); + return si; + } + + private NameImpl createSceneItemName(Item item) { + NameImpl name = new NameImpl(item.getElementName().getLocalPart()); + ItemDefinition def = item.getDefinition(); + if (def != null) { + name.setDisplayName(def.getDisplayName()); + name.setDescription(def.getDocumentation()); + } + name.setId(name.getSimpleName()); // todo reconsider + return name; + } + + + private SceneDeltaItemImpl createSceneDeltaItem(ReferenceDelta delta, SceneImpl owningScene, VisualizationContext context, Task task, + OperationResult result) + throws SchemaException { + SceneDeltaItemImpl di = createSceneDeltaItemCommon(delta, owningScene); + di.setOldValues(toSceneItemValuesRef(delta.getEstimatedOldValues(), context, task, result)); + + PrismReference reference = new PrismReference(delta.getElementName()); + try { + if (delta.getEstimatedOldValues() != null) { + reference.addAll(CloneUtil.cloneCollectionMembers(delta.getEstimatedOldValues())); + } + delta.applyToMatchingPath(reference); + } catch (SchemaException e) { + throw new SystemException("Couldn't visualize reference delta: " + delta + ": " + e.getMessage(), e); + } + computeAddedDeletedUnchangedRef(di, delta.getEstimatedOldValues(), reference.getValues(), context, task, result); + di.setNewValues(toSceneItemValuesRef(reference.getValues(), context, task, result)); + return di; + } + + + private List toSceneItemValues(Collection> values) { + List rv = new ArrayList<>(); + if (values != null) { + for (PrismPropertyValue value : values) { + if (value != null) { + SceneItemValueImpl siv = new SceneItemValueImpl(ValueDisplayUtil.toStringValue(value)); + siv.setSourceValue(value); + rv.add(siv); + } + } + } + return rv; + } + + private List toSceneItemValuesRef(Collection refValues, VisualizationContext context, Task task, OperationResult result) { + List rv = new ArrayList<>(); + if (refValues != null) { + for (PrismReferenceValue refValue : refValues) { + if (refValue != null) { + refValue = createRefValueWithObject(refValue, context, task, result); + SceneItemValueImpl itemValue = new SceneItemValueImpl(refValue.getTargetName() != null ? getOrig(refValue.getTargetName()) : refValue.getOid()); + itemValue.setSourceValue(refValue); + rv.add(itemValue); + } + } + } + return rv; + } + + @SuppressWarnings("unchecked") + private PrismReferenceValue createRefValueWithObject(PrismReferenceValue refValue, VisualizationContext context, Task task, OperationResult result) { + if (refValue.getObject() != null) { + return refValue; + } + PrismObject object = getObject(refValue.getOid(), (Class) refValue.getTargetTypeCompileTimeClass(), context, task, result); + if (object == null) { + return refValue; + } + refValue = refValue.clone(); + refValue.setObject(object); + return refValue; + } + + private NameImpl createSceneName(PrismObject object) { + NameImpl name = new NameImpl(object.getName() != null ? getOrig(object.getName()) : object.getOid()); + name.setId(object.getOid()); + ObjectType objectType = object.asObjectable(); + name.setDescription(objectType.getDescription()); + if (objectType instanceof UserType) { + name.setDisplayName(getOrig(((UserType) objectType).getFullName())); + } else if (objectType instanceof AbstractRoleType) { + name.setDisplayName(getOrig(((AbstractRoleType) objectType).getDisplayName())); + } + return name; + } + + private NameImpl createSceneName(String oid) { + NameImpl nv = new NameImpl(oid); + nv.setId(oid); + return nv; + } + +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/NameImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/NameImpl.java new file mode 100644 index 00000000000..cd560380a75 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/NameImpl.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.visualizer.output; + +import com.evolveum.midpoint.model.api.visualizer.Name; +import org.apache.commons.lang.Validate; + +import java.io.Serializable; + +/** + * @author mederly + */ +public class NameImpl implements Name { + + private final String simpleName; + private String displayName; + private String id; + private String description; + + public NameImpl(String simpleName) { + this.simpleName = simpleName; + } + + @Override + public String getSimpleName() { + return simpleName; + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @Override + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + @Override + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @Override + public String toString() { + return toDebugDump(); + } + + public String toDebugDump() { + return simpleName + " (" + displayName + "), id=" + id; + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneDeltaItemImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneDeltaItemImpl.java new file mode 100644 index 00000000000..d90e02bdad7 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneDeltaItemImpl.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.visualizer.output; + +import com.evolveum.midpoint.model.api.visualizer.SceneDeltaItem; +import com.evolveum.midpoint.model.api.visualizer.SceneItemValue; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.util.DebugDumpable; +import com.evolveum.midpoint.util.DebugUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * @author mederly + */ +public class SceneDeltaItemImpl extends SceneItemImpl implements SceneDeltaItem, DebugDumpable { + + @NotNull private List oldValues = Collections.emptyList(); + @NotNull private List addedValues = Collections.emptyList(); + @NotNull private List deletedValues = Collections.emptyList(); + @NotNull private List unchangedValues = Collections.emptyList(); + private ItemDelta sourceDelta; + + public SceneDeltaItemImpl(NameImpl name) { + super(name); + } + + @NotNull + @Override + public List getOldValues() { + return oldValues; + } + + public void setOldValues(@NotNull List oldValues) { + this.oldValues = oldValues; + } + + @NotNull + @Override + public List getAddedValues() { + return addedValues; + } + + public void setAddedValues(@NotNull List addedValues) { + this.addedValues = addedValues; + } + + @NotNull + public List getDeletedValues() { + return deletedValues; + } + + public void setDeletedValues(@NotNull List deletedValues) { + this.deletedValues = deletedValues; + } + + @NotNull + public List getUnchangedValues() { + return unchangedValues; + } + + public void setUnchangedValues(@NotNull List unchangedValues) { + this.unchangedValues = unchangedValues; + } + + @Override + public ItemDelta getSourceDelta() { + return sourceDelta; + } + + public void setSourceDelta(ItemDelta sourceDelta) { + this.sourceDelta = sourceDelta; + } + + @Override + public String debugDump() { + return debugDump(0); + } + + @Override + public String debugDump(int indent) { + StringBuilder sb = debugDumpCommon(indent); + if (sourceDelta != null) { + sb.append(" DELTA"); + } + sb.append("\n"); + DebugUtil.indentDebugDump(sb, indent+1); + sb.append("OLD: ").append(oldValues).append("\n"); + DebugUtil.indentDebugDump(sb, indent+1); + sb.append("NEW: ").append(newValues).append("\n"); + DebugUtil.indentDebugDump(sb, indent+1); + sb.append("ADDED: ").append(addedValues).append("\n"); + DebugUtil.indentDebugDump(sb, indent+1); + sb.append("DELETED: ").append(deletedValues).append("\n"); + DebugUtil.indentDebugDump(sb, indent+1); + sb.append("UNCHANGED: ").append(unchangedValues); + return sb.toString(); + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneImpl.java new file mode 100644 index 00000000000..777f9d7f756 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneImpl.java @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.visualizer.output; + +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.prism.PrismContainerDefinition; +import com.evolveum.midpoint.prism.PrismContainerValue; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.ChangeType; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.util.DebugDumpable; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author mederly + */ +public class SceneImpl implements Scene, DebugDumpable { + + private NameImpl name; + private ChangeType changeType; + private final List partialScenes = new ArrayList<>(); + private final List items = new ArrayList<>(); + private final SceneImpl owner; + private boolean operational; + private ItemPath sourceRelPath; + private ItemPath sourceAbsPath; + private PrismContainerValue sourceValue; + private PrismContainerDefinition sourceDefinition; + private ObjectDelta sourceDelta; + + public SceneImpl(SceneImpl owner) { + this.owner = owner; + } + + @Override + public NameImpl getName() { + return name; + } + + public void setName(NameImpl name) { + this.name = name; + } + + @Override + public ChangeType getChangeType() { + return changeType; + } + + public void setChangeType(ChangeType changeType) { + this.changeType = changeType; + } + + @NotNull + @Override + public List getPartialScenes() { + return partialScenes; + } + + public void addPartialScene(SceneImpl subscene) { + partialScenes.add(subscene); + } + + @NotNull + @Override + public List getItems() { + return items; + } + + public void addItem(SceneItemImpl item) { + items.add(item); + } + + @Override + public SceneImpl getOwner() { + return owner; + } + + @Override + public boolean isOperational() { + return operational; + } + + public void setOperational(boolean operational) { + this.operational = operational; + } + + public ItemPath getSourceRelPath() { + return sourceRelPath; + } + + public void setSourceRelPath(ItemPath sourceRelPath) { + this.sourceRelPath = sourceRelPath; + } + + @Override + public ItemPath getSourceAbsPath() { + return sourceAbsPath; + } + + public void setSourceAbsPath(ItemPath sourceAbsPath) { + this.sourceAbsPath = sourceAbsPath; + } + + @Override + public PrismContainerValue getSourceValue() { + return sourceValue; + } + + public void setSourceValue(PrismContainerValue sourceValue) { + this.sourceValue = sourceValue; + } + + @Override + public PrismContainerDefinition getSourceDefinition() { + return sourceDefinition; + } + + public void setSourceDefinition(PrismContainerDefinition sourceDefinition) { + this.sourceDefinition = sourceDefinition; + } + + @Override + public ObjectDelta getSourceDelta() { + return sourceDelta; + } + + public void setSourceDelta(ObjectDelta sourceDelta) { + this.sourceDelta = sourceDelta; + } + + @Override + public String debugDump() { + return debugDump(0); + } + + @Override + public String debugDump(int indent) { + StringBuilder sb = new StringBuilder(); + DebugUtil.indentDebugDump(sb, indent); + sb.append("Scene: "); + if (changeType != null) { + sb.append(changeType).append(": "); + } + if (name != null) { + sb.append(name.toDebugDump()); + } else { + sb.append("(unnamed)"); + } + sb.append(" [rel-path: ").append(sourceRelPath).append("]"); + sb.append(" [abs-path: ").append(sourceAbsPath).append("]"); + if (sourceValue != null) { + sb.append(" VAL"); + } + if (sourceDefinition != null) { + sb.append(" DEF(").append(sourceDefinition.getName().getLocalPart()).append("/").append(sourceDefinition.getDisplayName()).append(")"); + } + if (sourceDelta != null) { + sb.append(" DELTA"); + } + if (operational) { + sb.append(" OPER"); + } + for (SceneItemImpl dataItem : items) { + sb.append("\n"); + sb.append(dataItem.debugDump(indent+1)); + } + for (SceneImpl dataContext : partialScenes) { + sb.append("\n"); + sb.append(dataContext.debugDump(indent+1)); + } + return sb.toString(); + } + + public String getSourceOid() { + if (sourceValue != null && sourceValue.getParent() instanceof PrismObject) { + return ((PrismObject) sourceValue.getParent()).getOid(); + } else { + return null; + } + } + + public boolean isObjectValue() { + return sourceValue != null && sourceValue.getParent() instanceof PrismObject; + } + + public boolean isContainerValue() { + return sourceValue != null && !(sourceValue.getParent() instanceof PrismObject); + } + + public Long getSourceContainerValueId() { + if (isContainerValue()) { + return sourceValue.getId(); + } else { + return null; + } + } + + public boolean isFocusObject() { + return sourceDefinition != null && sourceDefinition.getCompileTimeClass() != null && FocusType.class.isAssignableFrom(sourceDefinition.getCompileTimeClass()); + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneItemImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneItemImpl.java new file mode 100644 index 00000000000..0b01052ea78 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneItemImpl.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.visualizer.output; + +import com.evolveum.midpoint.model.api.visualizer.SceneItem; +import com.evolveum.midpoint.model.api.visualizer.Name; +import com.evolveum.midpoint.model.api.visualizer.SceneItemValue; +import com.evolveum.midpoint.prism.Item; +import com.evolveum.midpoint.prism.ItemDefinition; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.util.DebugDumpable; +import com.evolveum.midpoint.util.DebugUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +import static org.apache.commons.lang.Validate.notNull; + +/** + * @author mederly + */ +public class SceneItemImpl implements SceneItem, DebugDumpable { + + protected final NameImpl name; + protected List newValues; + protected boolean operational; + protected Item sourceItem; + protected ItemPath sourceRelPath; + protected boolean descriptive; // added only as a description of container value being changed + + public SceneItemImpl(NameImpl name) { + notNull(name); + this.name = name; + } + + @Override + public Name getName() { + return name; + } + + @Override + public List getNewValues() { + return newValues; + } + + public void setNewValues(List newValues) { + this.newValues = newValues; + } + + @Override + public boolean isOperational() { + return operational; + } + + public void setOperational(boolean operational) { + this.operational = operational; + } + + public boolean isDescriptive() { + return descriptive; + } + + public void setDescriptive(boolean descriptive) { + this.descriptive = descriptive; + } + + @Override + public Item getSourceItem() { + return sourceItem; + } + + public void setSourceItem(Item sourceItem) { + this.sourceItem = sourceItem; + } + + public ItemPath getSourceRelPath() { + return sourceRelPath; + } + + public void setSourceRelPath(ItemPath sourceRelPath) { + this.sourceRelPath = sourceRelPath; + } + + @Override + public String debugDump() { + return debugDump(0); + } + + @Override + public String debugDump(int indent) { + StringBuilder sb = debugDumpCommon(indent); + if (descriptive) { + sb.append(" DESC"); + } + sb.append("\n"); + DebugUtil.indentDebugDump(sb, indent+1); + sb.append("VALUES: ").append(newValues); + return sb.toString(); + } + + @NotNull + protected StringBuilder debugDumpCommon(int indent) { + StringBuilder sb = new StringBuilder(); + DebugUtil.indentDebugDump(sb, indent); + sb.append("Item: ").append(name).append(" [rel-path: ").append(sourceRelPath).append("]"); + if (sourceItem != null) { + sb.append(" ITEM"); + final ItemDefinition def = sourceItem.getDefinition(); + if (def != null) { + sb.append(" DEF(").append(def.getName().getLocalPart()).append("/").append(def.getDisplayName()).append(":").append(def.getDisplayOrder()).append(")"); + } + } + if (operational) { + sb.append(" OPER"); + } + return sb; + } + + public ItemDefinition getSourceDefinition() { + return sourceItem != null ? sourceItem.getDefinition() : null; + } +} diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneItemValueImpl.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneItemValueImpl.java new file mode 100644 index 00000000000..d5a22cefdd6 --- /dev/null +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/visualizer/output/SceneItemValueImpl.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.model.impl.visualizer.output; + +import com.evolveum.midpoint.model.api.visualizer.SceneItemValue; +import com.evolveum.midpoint.prism.PrismValue; + +/** + * @author mederly + */ +public class SceneItemValueImpl implements SceneItemValue { + + private final String text; + private PrismValue sourceValue; + + public SceneItemValueImpl(String text) { + this.text = text; + } + + @Override + public String getText() { + return text; + } + + @Override + public PrismValue getSourceValue() { + return sourceValue; + } + + public void setSourceValue(PrismValue sourceValue) { + this.sourceValue = sourceValue; + } + + @Override + public String toString() { + return "'" + text + "'" + (sourceValue != null ? "*" : ""); + } +} diff --git a/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/visualizer/TestVisualizer.java b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/visualizer/TestVisualizer.java new file mode 100644 index 00000000000..3c4312683a4 --- /dev/null +++ b/model/model-impl/src/test/java/com/evolveum/midpoint/model/impl/visualizer/TestVisualizer.java @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.evolveum.midpoint.model.impl.visualizer; + +import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.api.context.ModelProjectionContext; +import com.evolveum.midpoint.model.api.visualizer.Scene; +import com.evolveum.midpoint.model.impl.AbstractInternalModelIntegrationTest; +import com.evolveum.midpoint.model.impl.migrator.Migrator; +import com.evolveum.midpoint.model.impl.visualizer.output.SceneImpl; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.delta.builder.DeltaBuilder; +import com.evolveum.midpoint.prism.polystring.PolyString; +import com.evolveum.midpoint.prism.util.PrismAsserts; +import com.evolveum.midpoint.prism.util.PrismTestUtil; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.schema.MidPointPrismContextFactory; +import com.evolveum.midpoint.schema.constants.MidPointConstants; +import com.evolveum.midpoint.schema.constants.ObjectTypes; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.test.IntegrationTestTools; +import com.evolveum.midpoint.test.util.TestUtil; +import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.PrettyPrinter; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; +import difflib.DiffUtils; +import difflib.Patch; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.Test; +import org.xml.sax.SAXException; +import sun.security.provider.SHA; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import static com.evolveum.midpoint.schema.constants.ObjectTypes.*; +import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.createObjectRef; +import static com.evolveum.midpoint.test.IntegrationTestTools.display; +import static com.evolveum.midpoint.test.util.TestUtil.*; +import static org.apache.commons.collections.CollectionUtils.addIgnoreNull; +import static org.testng.AssertJUnit.*; + +/** + * @author mederly + * + */ +@ContextConfiguration(locations = {"classpath:ctx-model-test-main.xml"}) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) +public class TestVisualizer extends AbstractInternalModelIntegrationTest { + + @Autowired + private Visualizer visualizer; + + @Autowired + private PrismContext prismContext; + + @Autowired + private TaskManager taskManager; + + @BeforeSuite + public void setup() throws SchemaException, SAXException, IOException { + PrettyPrinter.setDefaultNamespacePrefix(MidPointConstants.NS_MIDPOINT_PUBLIC_PREFIX); + PrismTestUtil.resetPrismContext(MidPointPrismContextFactory.FACTORY); + } + + @Test + public void test100UserBasic() throws SchemaException { + final String TEST_NAME = "test100UserBasic"; + Task task = createTask(TEST_NAME); + + PrismObject u = prismContext.createObject(UserType.class); + u.setOid("123"); + u.asObjectable().setName(new PolyStringType("user123")); + u.asObjectable().setFullName(new PolyStringType("User User123")); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualize(u, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test110UserWithContainers() throws SchemaException { + final String TEST_NAME = "test101UserWithContainers"; + Task task = createTask(TEST_NAME); + + PrismObject u = prismContext.createObject(UserType.class); + UserType ut = u.asObjectable(); + u.setOid("456"); + ut.setName(new PolyStringType("user456")); + ut.setFullName(new PolyStringType("User User456")); + ut.setActivation(new ActivationType(prismContext)); + ut.getActivation().setAdministrativeStatus(ActivationStatusType.ENABLED); + ut.getActivation().setValidTo(XmlTypeConverter.createXMLGregorianCalendar(2020, 1, 1, 0, 0, 0)); + AssignmentType ass1 = new AssignmentType(prismContext); + ass1.setActivation(new ActivationType(prismContext)); + ass1.getActivation().setAdministrativeStatus(ActivationStatusType.ENABLED); + ass1.getActivation().setValidTo(XmlTypeConverter.createXMLGregorianCalendar(2019, 1, 1, 0, 0, 0)); + ass1.setTargetRef(createObjectRef(ROLE_SUPERUSER_OID, ROLE)); + ut.getAssignment().add(ass1); + AssignmentType ass2 = new AssignmentType(prismContext); + ass2.setTargetRef(createObjectRef("777", ROLE)); + ut.getAssignment().add(ass2); + AssignmentType ass3 = new AssignmentType(prismContext); + ass3.setConstruction(new ConstructionType(prismContext)); + ass3.getConstruction().setResourceRef(createObjectRef(RESOURCE_DUMMY_OID, RESOURCE)); + ut.getAssignment().add(ass3); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualize(u, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test200UserDeltaBasic() throws SchemaException { + final String TEST_NAME = "test200UserDeltaBasic"; + Task task = createTask(TEST_NAME); + + ObjectDelta delta = DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_NAME).replace("admin") + .asObjectDelta(USER_ADMINISTRATOR_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta((ObjectDelta) delta, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test210UserDeltaContainers() throws SchemaException { + final String TEST_NAME = "test210UserDeltaContainers"; + Task task = createTask(TEST_NAME); + + AssignmentType ass1 = new AssignmentType(prismContext); + ass1.setActivation(new ActivationType(prismContext)); + ass1.getActivation().setAdministrativeStatus(ActivationStatusType.ENABLED); + ass1.getActivation().setValidTo(XmlTypeConverter.createXMLGregorianCalendar(2017, 1, 1, 0, 0, 0)); + ass1.setTargetRef(createObjectRef(ROLE_SUPERUSER_OID, ROLE)); + + ObjectDelta delta = DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_NAME).replace("admin") + .item(UserType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS).replace(ActivationStatusType.ENABLED) + .item(UserType.F_ASSIGNMENT, 1, AssignmentType.F_TARGET_REF).replace(createObjectRef("123", ROLE).asReferenceValue()) + .item(UserType.F_ASSIGNMENT, 1, AssignmentType.F_DESCRIPTION).add("suspicious") + .item(UserType.F_ASSIGNMENT).add(ass1) + .asObjectDelta(USER_ADMINISTRATOR_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta((ObjectDelta) delta, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test212UserDeltaContainerSimple() throws SchemaException { + final String TEST_NAME = "test212UserDeltaContainerSimple"; + Task task = createTask(TEST_NAME); + + ObjectDelta delta = DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_ACTIVATION, ActivationType.F_EFFECTIVE_STATUS).replace(ActivationStatusType.ENABLED) + .item(UserType.F_ACTIVATION, ActivationType.F_ENABLE_TIMESTAMP).replace(XmlTypeConverter.createXMLGregorianCalendar(new Date())) + .asObjectDelta(USER_ADMINISTRATOR_OID); + + /// WHEN + displayWhen(TEST_NAME); + final List scenes = visualizer.visualizeDeltas((List) Collections.singletonList(delta), task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scenes", scenes); + + // TODO some asserts + } + + @Test + public void test220UserContainerReplace() throws SchemaException { + final String TEST_NAME = "test220UserContainerReplace"; + Task task = createTask(TEST_NAME); + + AssignmentType ass1 = new AssignmentType(prismContext); + ass1.setActivation(new ActivationType(prismContext)); + ass1.getActivation().setAdministrativeStatus(ActivationStatusType.DISABLED); + ass1.getActivation().setValidFrom(XmlTypeConverter.createXMLGregorianCalendar(2010, 1, 1, 0, 0, 0)); + ass1.setTargetRef(createObjectRef(ROLE_SUPERUSER_OID, ROLE)); + + ActivationType act1 = new ActivationType(prismContext); + act1.setAdministrativeStatus(ActivationStatusType.DISABLED); + + ObjectDelta delta = DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_NAME).replace("admin") + .item(UserType.F_ACTIVATION).replace(act1) + .item(UserType.F_ASSIGNMENT).replace(ass1) + .asObjectDelta(USER_ADMINISTRATOR_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta((ObjectDelta) delta, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test230UserContainerDelete() throws SchemaException { + final String TEST_NAME = "test230UserContainerDelete"; + Task task = createTask(TEST_NAME); + + AssignmentType ass1 = new AssignmentType(prismContext); + ass1.setId(1L); + + AssignmentType ass2 = new AssignmentType(prismContext); + ass2.setId(99999L); + + ObjectDelta delta = DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_NAME).replace("admin") + .item(UserType.F_ASSIGNMENT).delete(ass1, ass2) + .asObjectDelta(USER_ADMINISTRATOR_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta((ObjectDelta) delta, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test300UserAssignmentPreview() throws Exception { + final String TEST_NAME = "test300UserAssignmentPreview"; + Task task = createTask(TEST_NAME); + + PrismObject jack = getUser(USER_JACK_OID); + display("jack", jack); + + AssignmentType ass1 = new AssignmentType(prismContext); + ass1.setConstruction(new ConstructionType(prismContext)); + ass1.getConstruction().setResourceRef(createObjectRef(RESOURCE_DUMMY_OID, RESOURCE)); + + ObjectDelta delta = (ObjectDelta) DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_ASSIGNMENT).add(ass1) + .asObjectDelta(USER_JACK_OID); + + delta.applyDefinition(jack.getDefinition()); + + /// WHEN + displayWhen(TEST_NAME); + ModelContext modelContext = modelInteractionService.previewChanges(Collections.>singletonList(delta), null, task, task.getResult()); + List> primaryDeltas = new ArrayList<>(); + List> secondaryDeltas = new ArrayList<>(); + fillDeltas(modelContext, primaryDeltas, secondaryDeltas); + + List primaryScenes = modelInteractionService.visualizeDeltas(primaryDeltas, task, task.getResult()); + List secondaryScenes = modelInteractionService.visualizeDeltas(secondaryDeltas, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("primary scenes", primaryScenes); + display("secondary scenes", secondaryScenes); + + // TODO some asserts + } + + @Test + public void test305UserAssignmentAdd() throws Exception { + final String TEST_NAME = "test305UserAssignmentAdd"; + Task task = createTask(TEST_NAME); + + display("jack", getUser(USER_JACK_OID)); + + AssignmentType ass1 = new AssignmentType(); + ass1.setConstruction(new ConstructionType()); + ass1.getConstruction().setResourceRef(createObjectRef(RESOURCE_DUMMY_OID, RESOURCE)); + + ObjectDelta delta = (ObjectDelta) DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_ASSIGNMENT).add(ass1) + .asObjectDelta(USER_JACK_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta(delta, task, task.getResult()); + + modelService.executeChanges(Collections.>singletonList(delta), null, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + display("jack with assignment", getUser(USER_JACK_OID)); + + // TODO some asserts + } + + @Test + public void test307UserDisablePreview() throws Exception { + final String TEST_NAME = "test307UserDisablePreview"; + Task task = createTask(TEST_NAME); + + ObjectDelta delta = (ObjectDelta) DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_ACTIVATION, ActivationType.F_ADMINISTRATIVE_STATUS).replace(ActivationStatusType.DISABLED) + .asObjectDelta(USER_JACK_OID); + + /// WHEN + displayWhen(TEST_NAME); + ModelContext modelContext = modelInteractionService.previewChanges(Collections.>singletonList(delta), null, task, task.getResult()); + List> primaryDeltas = new ArrayList<>(); + List> secondaryDeltas = new ArrayList<>(); + fillDeltas(modelContext, primaryDeltas, secondaryDeltas); + + List primaryScenes = modelInteractionService.visualizeDeltas(primaryDeltas, task, task.getResult()); + List secondaryScenes = modelInteractionService.visualizeDeltas(secondaryDeltas, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("primary scenes", primaryScenes); + display("secondary scenes", secondaryScenes); + + // TODO some asserts + } + + protected void fillDeltas(ModelContext modelContext, List> primaryDeltas, + List> secondaryDeltas) throws SchemaException { + if (modelContext != null) { + if (modelContext.getFocusContext() != null) { + addIgnoreNull(primaryDeltas, modelContext.getFocusContext().getPrimaryDelta()); + addIgnoreNull(secondaryDeltas, modelContext.getFocusContext().getSecondaryDelta()); + } + for (ModelProjectionContext projCtx : modelContext.getProjectionContexts()) { + addIgnoreNull(primaryDeltas, projCtx.getPrimaryDelta()); + addIgnoreNull(secondaryDeltas, projCtx.getExecutableDelta()); + } + } + display("primary deltas", primaryDeltas); + display("secondary deltas", secondaryDeltas); + } + + private String dummyAccountOid; + + @Test + public void test310UserLinkRefDelete() throws Exception { + final String TEST_NAME = "test310UserLinkRefDelete"; + Task task = createTask(TEST_NAME); + + UserType jack = getUser(USER_JACK_OID).asObjectable(); + assertEquals("wrong # of linkrefs", 1, jack.getLinkRef().size()); + dummyAccountOid = jack.getLinkRef().get(0).getOid(); + + ObjectDelta delta = (ObjectDelta) DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_LINK_REF).delete(createObjectRef(dummyAccountOid, SHADOW).asReferenceValue()) + .asObjectDelta(USER_JACK_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta(delta, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test320UserLinkRefAdd() throws Exception { + final String TEST_NAME = "test320UserLinkRefAdd"; + Task task = createTask(TEST_NAME); + + ObjectDelta delta = (ObjectDelta) DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_LINK_REF).add(createObjectRef(dummyAccountOid, SHADOW).asReferenceValue()) + .asObjectDelta(USER_JACK_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta(delta, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test330UserLinkRefReplaceNoOp() throws Exception { + final String TEST_NAME = "test330UserLinkRefReplaceNoOp"; + Task task = createTask(TEST_NAME); + + ObjectDelta delta = (ObjectDelta) DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_LINK_REF).replace(createObjectRef(dummyAccountOid, SHADOW).asReferenceValue()) + .asObjectDelta(USER_JACK_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta(delta, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + + @Test + public void test340UserLinkRefReplaceOp() throws Exception { + final String TEST_NAME = "test340UserLinkRefReplaceOp"; + Task task = createTask(TEST_NAME); + + ObjectDelta delta = (ObjectDelta) DeltaBuilder.deltaFor(UserType.class, prismContext) + .item(UserType.F_LINK_REF).replace(createObjectRef("777", SHADOW).asReferenceValue()) + .asObjectDelta(USER_JACK_OID); + + /// WHEN + displayWhen(TEST_NAME); + final Scene scene = visualizer.visualizeDelta(delta, task, task.getResult()); + + // THEN + displayThen(TEST_NAME); + display("scene", scene); + + // TODO some asserts + } + +} diff --git a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java index d7021982eee..61ff205af0b 100644 --- a/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java +++ b/model/model-test/src/main/java/com/evolveum/midpoint/model/test/AbstractModelIntegrationTest.java @@ -181,7 +181,7 @@ /** * Abstract framework for an integration test that is placed on top of a model API. - * This provides complete environment that the test should need, e.g model service instance, repository, provisionig, + * This provides complete environment that the test should need, e.g model service instance, repository, provisioning, * dummy auditing, etc. It also implements lots of useful methods to make writing the tests easier. * * @author Radovan Semancik diff --git a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/NotificationManager.java b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/NotificationManager.java index 1bf6b70bf79..b7ee4b6e1b6 100644 --- a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/NotificationManager.java +++ b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/NotificationManager.java @@ -19,11 +19,9 @@ import com.evolveum.midpoint.notifications.api.events.Event; import com.evolveum.midpoint.notifications.api.events.WorkflowEventCreator; import com.evolveum.midpoint.notifications.api.transports.Transport; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.xml.ns._public.common.common_3.EventHandlerType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; /** * @author mederly @@ -34,9 +32,7 @@ public interface NotificationManager { void registerTransport(String name, Transport transport); Transport getTransport(String name); - void registerWorkflowEventCreator(Class clazz, WorkflowEventCreator workflowEventCreator); - - WorkflowEventCreator getWorkflowEventCreator(PrismObject instanceState); + WorkflowEventCreator getWorkflowEventCreator(Task wfTask); // event may be null void processEvent(Event event); diff --git a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkItemEvent.java b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkItemEvent.java index 56de7f13258..22ada592f11 100644 --- a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkItemEvent.java +++ b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkItemEvent.java @@ -21,6 +21,9 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator; import com.evolveum.midpoint.xml.ns._public.common.common_3.EventCategoryType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; +import org.apache.commons.lang.Validate; import javax.xml.namespace.QName; @@ -31,11 +34,15 @@ */ public class WorkItemEvent extends WorkflowEvent { + private final WorkItemType workItem; private String workItemName; private SimpleObjectRef assignee; - public WorkItemEvent(LightweightIdentifierGenerator lightweightIdentifierGenerator, ChangeType changeType) { - super(lightweightIdentifierGenerator, changeType); + public WorkItemEvent(LightweightIdentifierGenerator lightweightIdentifierGenerator, ChangeType changeType, WorkItemType workItem, + WfContextType workflowContext) { + super(lightweightIdentifierGenerator, changeType, workflowContext); + Validate.notNull(workItem); + this.workItem = workItem; } public String getWorkItemName() { diff --git a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowEvent.java b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowEvent.java index a809b7da008..beb7d535be4 100644 --- a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowEvent.java +++ b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowEvent.java @@ -17,68 +17,36 @@ package com.evolveum.midpoint.notifications.api.events; import com.evolveum.midpoint.notifications.api.OperationStatus; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator; import com.evolveum.midpoint.wf.util.ApprovalUtils; -import com.evolveum.midpoint.xml.ns._public.common.common_3.EventOperationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.EventStatusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; - -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ItemApprovalProcessState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ItemApprovalRequestType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.PrimaryChangeProcessorState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessorSpecificState; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.Validate; -import java.io.Serializable; - /** * @author mederly */ abstract public class WorkflowEvent extends BaseEvent { - private String processInstanceName; - private PrismObject processInstanceState; - private String operationStatusCustom; // exact string representation of the status (useful for work items that return custom statuses) - private ChangeType changeType; // ADD = process/task start, DELETE = process/task finish (for now) + private final WfContextType workflowContext; + private final ChangeType changeType; // ADD = process/task start, DELETE = process/task finish (for now) - public WorkflowEvent(LightweightIdentifierGenerator lightweightIdentifierGenerator, ChangeType changeType) { + public WorkflowEvent(LightweightIdentifierGenerator lightweightIdentifierGenerator, ChangeType changeType, WfContextType workflowContext) { super(lightweightIdentifierGenerator); Validate.notNull(changeType, "changeType is null"); this.changeType = changeType; + Validate.notNull(workflowContext, "workflowContext is null"); + this.workflowContext = workflowContext; } public String getProcessInstanceName() { - return processInstanceName; - } - - public void setProcessInstanceName(String processInstanceName) { - this.processInstanceName = processInstanceName; - } - - public PrismObject getProcessInstanceState() { - return processInstanceState; - } - - public void setProcessInstanceState(PrismObject processInstanceState) { - this.processInstanceState = processInstanceState; + return workflowContext.getProcessInstanceName(); } public OperationStatus getOperationStatus() { - return resultToStatus(changeType, operationStatusCustom); - } - - public String getOperationStatusCustom() { - return operationStatusCustom; - } - - public void setOperationStatusCustom(String operationStatusCustom) { - this.operationStatusCustom = operationStatusCustom; + return resultToStatus(changeType, workflowContext.getAnswer()); } @Override @@ -128,52 +96,28 @@ public boolean isRelatedToItem(ItemPath itemPath) { return false; } - public ProcessorSpecificState getProcessorSpecificState() { - if (processInstanceState == null) { - return null; - } - return ((ProcessInstanceState) processInstanceState.asObjectable()).getProcessorSpecificState(); + public WfProcessorSpecificStateType getProcessorSpecificState() { + return workflowContext.getProcessorSpecificState(); } - public ProcessSpecificState getProcessSpecificState() { - if (processInstanceState == null) { - return null; - } - return ((ProcessInstanceState) processInstanceState.asObjectable()).getProcessSpecificState(); + public WfProcessSpecificStateType getProcessSpecificState() { + return workflowContext.getProcessSpecificState(); } - public PrimaryChangeProcessorState getPrimaryChangeProcessorState() { - ProcessorSpecificState state = getProcessorSpecificState(); - if (state instanceof PrimaryChangeProcessorState) { - return (PrimaryChangeProcessorState) state; + public WfPrimaryChangeProcessorStateType getPrimaryChangeProcessorState() { + WfProcessorSpecificStateType state = getProcessorSpecificState(); + if (state instanceof WfPrimaryChangeProcessorStateType) { + return (WfPrimaryChangeProcessorStateType) state; } else { return null; } } // the following three methods are specific to ItemApproval process - public ItemApprovalProcessState getItemApprovalProcessState() { - ProcessSpecificState state = getProcessSpecificState(); - if (state instanceof ItemApprovalProcessState) { - return (ItemApprovalProcessState) state; - } else { - return null; - } - } - - public ItemApprovalRequestType getItemApprovalRequest() { - ItemApprovalProcessState state = getItemApprovalProcessState(); - if (state != null) { - return state.getApprovalRequest(); - } else { - return null; - } - } - - public Object getItemToApprove() { - ItemApprovalRequestType request = getItemApprovalRequest(); - if (request != null) { - return request.getItemToApprove(); + public ItemApprovalProcessStateType getItemApprovalProcessState() { + WfProcessSpecificStateType state = getProcessSpecificState(); + if (state instanceof ItemApprovalProcessStateType) { + return (ItemApprovalProcessStateType) state; } else { return null; } @@ -183,9 +127,9 @@ public Object getItemToApprove() { public String toString() { return "WorkflowEvent{" + "event=" + super.toString() + - ", processInstanceName='" + processInstanceName + '\'' + + ", processInstanceName='" + getProcessInstanceName() + '\'' + ", changeType=" + changeType + - ", operationStatusCustom=" + operationStatusCustom + + ", answer=" + workflowContext.getAnswer() + '}'; } diff --git a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowEventCreator.java b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowEventCreator.java index d11b6e28959..953ac34e28b 100644 --- a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowEventCreator.java +++ b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowEventCreator.java @@ -16,9 +16,9 @@ package com.evolveum.midpoint.notifications.api.events; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; /** * Used to create (fill-in) a workflow event based on information passed from workflow module. @@ -35,11 +35,11 @@ */ public interface WorkflowEventCreator { - WorkflowProcessEvent createWorkflowProcessStartEvent(PrismObject instanceState, OperationResult result); + WorkflowProcessEvent createWorkflowProcessStartEvent(Task wfTask, OperationResult result); - WorkflowProcessEvent createWorkflowProcessEndEvent(PrismObject instanceState, OperationResult result); + WorkflowProcessEvent createWorkflowProcessEndEvent(Task wfTask, OperationResult result); - WorkItemEvent createWorkItemCreateEvent(String workItemName, String assigneeOid, PrismObject instanceState); + WorkItemEvent createWorkItemCreateEvent(WorkItemType workItem, Task wfTask, OperationResult result); - WorkItemEvent createWorkItemCompleteEvent(String workItemName, String assigneeOid, PrismObject instanceState, String decision); + WorkItemEvent createWorkItemCompleteEvent(WorkItemType workItem, Task wfTask, OperationResult result); } diff --git a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowProcessEvent.java b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowProcessEvent.java index eeb93646d1c..86e265eee15 100644 --- a/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowProcessEvent.java +++ b/model/notifications-api/src/main/java/com/evolveum/midpoint/notifications/api/events/WorkflowProcessEvent.java @@ -19,14 +19,15 @@ import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator; import com.evolveum.midpoint.xml.ns._public.common.common_3.EventCategoryType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType; /** * @author mederly */ public class WorkflowProcessEvent extends WorkflowEvent { - public WorkflowProcessEvent(LightweightIdentifierGenerator lightweightIdentifierGenerator, ChangeType changeType) { - super(lightweightIdentifierGenerator, changeType); + public WorkflowProcessEvent(LightweightIdentifierGenerator lightweightIdentifierGenerator, ChangeType changeType, WfContextType workflowContext) { + super(lightweightIdentifierGenerator, changeType, workflowContext); } @Override diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/NotificationManagerImpl.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/NotificationManagerImpl.java index 33ca4e8c683..590a3f5e118 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/NotificationManagerImpl.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/NotificationManagerImpl.java @@ -22,7 +22,6 @@ import com.evolveum.midpoint.notifications.api.events.WorkflowEventCreator; import com.evolveum.midpoint.notifications.api.transports.Transport; import com.evolveum.midpoint.notifications.impl.events.workflow.DefaultWorkflowEventCreator; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; @@ -33,14 +32,10 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.EventHandlerType; import com.evolveum.midpoint.xml.ns._public.common.common_3.NotificationConfigurationType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; -import javax.xml.bind.JAXBElement; - import java.util.HashMap; /** @@ -63,7 +58,6 @@ public class NotificationManagerImpl implements NotificationManager { private HashMap,EventHandler> handlers = new HashMap,EventHandler>(); private HashMap transports = new HashMap(); - private HashMap,WorkflowEventCreator> workflowEventCreators = new HashMap<>(); // key = class of type ProcessInstanceState public void registerEventHandler(Class clazz, EventHandler handler) { LOGGER.trace("Registering event handler " + handler + " for " + clazz); @@ -98,22 +92,9 @@ public Transport getTransport(String name) { } @Override - public void registerWorkflowEventCreator(Class clazz, WorkflowEventCreator workflowEventCreator) { - // TODO think again about this mechanism - if (workflowEventCreators.containsKey(clazz)) { - LOGGER.warn("Multiple registrations of workflow event creators for class {}", clazz.getName()); - } - workflowEventCreators.put(clazz, workflowEventCreator); - } - - @Override - public WorkflowEventCreator getWorkflowEventCreator(PrismObject instanceState) { - WorkflowEventCreator workflowEventCreator = workflowEventCreators.get(instanceState.asObjectable().getClass()); - if (workflowEventCreator == null) { - return defaultWorkflowEventCreator; - } else { - return workflowEventCreator; - } + public WorkflowEventCreator getWorkflowEventCreator(Task wfTask) { + // TODO + return defaultWorkflowEventCreator; } // event may be null diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/WorkflowListener.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/WorkflowListener.java index 795fbe92891..7a263c9ea87 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/WorkflowListener.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/WorkflowListener.java @@ -21,15 +21,15 @@ import com.evolveum.midpoint.notifications.api.events.WorkflowEvent; import com.evolveum.midpoint.notifications.api.events.WorkflowEventCreator; import com.evolveum.midpoint.notifications.api.events.WorkflowProcessEvent; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.api.ProcessListener; import com.evolveum.midpoint.wf.api.WorkItemListener; import com.evolveum.midpoint.wf.api.WorkflowManager; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -67,30 +67,30 @@ public void init() { } @Override - public void onProcessInstanceStart(PrismObject instanceState, OperationResult result) { - WorkflowEventCreator workflowEventCreator = notificationManager.getWorkflowEventCreator(instanceState); - WorkflowProcessEvent event = workflowEventCreator.createWorkflowProcessStartEvent(instanceState, result); + public void onProcessInstanceStart(Task wfTask, OperationResult result) { + WorkflowEventCreator workflowEventCreator = notificationManager.getWorkflowEventCreator(wfTask); + WorkflowProcessEvent event = workflowEventCreator.createWorkflowProcessStartEvent(wfTask, result); processEvent(event, result); } @Override - public void onProcessInstanceEnd(PrismObject instanceState, OperationResult result) { - WorkflowEventCreator workflowEventCreator = notificationManager.getWorkflowEventCreator(instanceState); - WorkflowProcessEvent event = workflowEventCreator.createWorkflowProcessEndEvent(instanceState, result); + public void onProcessInstanceEnd(Task wfTask, OperationResult result) { + WorkflowEventCreator workflowEventCreator = notificationManager.getWorkflowEventCreator(wfTask); + WorkflowProcessEvent event = workflowEventCreator.createWorkflowProcessEndEvent(wfTask, result); processEvent(event, result); } @Override - public void onWorkItemCreation(String workItemName, String assigneeOid, PrismObject instanceState) { - WorkflowEventCreator workflowEventCreator = notificationManager.getWorkflowEventCreator(instanceState); - WorkItemEvent event = workflowEventCreator.createWorkItemCreateEvent(workItemName, assigneeOid, instanceState); + public void onWorkItemCreation(WorkItemType workItem, Task wfTask, OperationResult result) { + WorkflowEventCreator workflowEventCreator = notificationManager.getWorkflowEventCreator(wfTask); + WorkItemEvent event = workflowEventCreator.createWorkItemCreateEvent(workItem, wfTask, result); processEvent(event); } @Override - public void onWorkItemCompletion(String workItemName, String assigneeOid, PrismObject instanceState, String decision) { - WorkflowEventCreator workflowEventCreator = notificationManager.getWorkflowEventCreator(instanceState); - WorkItemEvent event = workflowEventCreator.createWorkItemCompleteEvent(workItemName, assigneeOid, instanceState, decision); + public void onWorkItemCompletion(WorkItemType workItem, Task wfTask, OperationResult result) { + WorkflowEventCreator workflowEventCreator = notificationManager.getWorkflowEventCreator(wfTask); + WorkItemEvent event = workflowEventCreator.createWorkItemCompleteEvent(workItem, wfTask, result); processEvent(event); } diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/events/workflow/DefaultWorkflowEventCreator.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/events/workflow/DefaultWorkflowEventCreator.java index f29df4ab616..f0f17acf291 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/events/workflow/DefaultWorkflowEventCreator.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/events/workflow/DefaultWorkflowEventCreator.java @@ -23,20 +23,15 @@ import com.evolveum.midpoint.notifications.api.events.WorkflowProcessEvent; import com.evolveum.midpoint.notifications.impl.NotificationsUtil; import com.evolveum.midpoint.notifications.impl.SimpleObjectRefImpl; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.LightweightIdentifierGenerator; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.PrimaryChangeProcessorState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; - +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; - /** * @author mederly */ @@ -52,64 +47,44 @@ public class DefaultWorkflowEventCreator implements WorkflowEventCreator { @Autowired private NotificationManager notificationManager; - @PostConstruct - public void init() { - notificationManager.registerWorkflowEventCreator(ProcessInstanceState.class, this); - } - @Override - public WorkflowProcessEvent createWorkflowProcessStartEvent(PrismObject instanceState, OperationResult result) { - return createWorkflowProcessEvent(instanceState, ChangeType.ADD, result); + public WorkflowProcessEvent createWorkflowProcessStartEvent(Task wfTask, OperationResult result) { + return createWorkflowProcessEvent(wfTask, ChangeType.ADD, result); } @Override - public WorkflowProcessEvent createWorkflowProcessEndEvent(PrismObject instanceState, OperationResult result) { - return createWorkflowProcessEvent(instanceState, ChangeType.DELETE, result); + public WorkflowProcessEvent createWorkflowProcessEndEvent(Task wfTask, OperationResult result) { + return createWorkflowProcessEvent(wfTask, ChangeType.DELETE, result); } - private WorkflowProcessEvent createWorkflowProcessEvent(PrismObject instanceState, ChangeType changeType, OperationResult result) { - WorkflowProcessEvent event = new WorkflowProcessEvent(lightweightIdentifierGenerator, changeType); - fillInEvent(event, instanceState.asObjectable().getProcessInstanceName(), instanceState, instanceState.asObjectable().getAnswer(), result); + private WorkflowProcessEvent createWorkflowProcessEvent(Task wfTask, ChangeType changeType, OperationResult result) { + WorkflowProcessEvent event = new WorkflowProcessEvent(lightweightIdentifierGenerator, changeType, wfTask.getWorkflowContext()); + fillInEvent(event, wfTask); return event; } - private void fillInEvent(WorkflowEvent event, String instanceName, PrismObject instanceState, String decision, OperationResult result) { - event.setProcessInstanceName(instanceName); - event.setOperationStatusCustom(decision); - event.setProcessInstanceState(instanceState); - event.setRequester(new SimpleObjectRefImpl(notificationsUtil, instanceState.asObjectable().getRequesterOid())); - if (instanceState.asObjectable().getObjectOid() != null) { - event.setRequestee(new SimpleObjectRefImpl(notificationsUtil, instanceState.asObjectable().getObjectOid())); - } - - // fill-in requestee (for primary approval process variables) - - if (event.getRequestee() == null && instanceState.asObjectable().getProcessorSpecificState() instanceof PrimaryChangeProcessorState) { - PrimaryChangeProcessorState pcpState = (PrimaryChangeProcessorState) instanceState.asObjectable().getProcessorSpecificState(); - if (pcpState.getObjectToBeAdded() != null) { - ObjectType objectToBeAdded = pcpState.getObjectToBeAdded(); - if (objectToBeAdded instanceof UserType) { - event.setRequestee(new SimpleObjectRefImpl(notificationsUtil, objectToBeAdded)); - } - } + private void fillInEvent(WorkflowEvent event, Task wfTask) { + WfContextType wfc = wfTask.getWorkflowContext(); + event.setRequester(new SimpleObjectRefImpl(notificationsUtil, wfc.getRequesterRef())); + if (wfc.getObjectRef() != null) { + event.setRequestee(new SimpleObjectRefImpl(notificationsUtil, wfc.getObjectRef())); } + // TODO what if requestee is yet to be created? } @Override - public WorkItemEvent createWorkItemCreateEvent(String workItemName, String assigneeOid, PrismObject instanceState) { - return createWorkItemEvent(workItemName, assigneeOid, instanceState, ChangeType.ADD, null); + public WorkItemEvent createWorkItemCreateEvent(WorkItemType workItem, Task wfTask, OperationResult result) { + return createWorkItemEvent(workItem, wfTask, ChangeType.ADD); } @Override - public WorkItemEvent createWorkItemCompleteEvent(String workItemName, String assigneeOid, PrismObject instanceState, String decision) { - return createWorkItemEvent(workItemName, assigneeOid, instanceState, ChangeType.DELETE, decision); + public WorkItemEvent createWorkItemCompleteEvent(WorkItemType workItem, Task wfTask, OperationResult result) { + return createWorkItemEvent(workItem, wfTask, ChangeType.DELETE); } - private WorkItemEvent createWorkItemEvent(String workItemName, String assigneeOid, PrismObject instanceState, ChangeType changeType, String decision) { - WorkItemEvent event = new WorkItemEvent(lightweightIdentifierGenerator, changeType); - event.setWorkItemName(workItemName); - event.setAssignee(new SimpleObjectRefImpl(notificationsUtil, assigneeOid)); - fillInEvent(event, instanceState.asObjectable().getProcessInstanceName(), instanceState, decision, new OperationResult("dummy")); + private WorkItemEvent createWorkItemEvent(WorkItemType workItemType, Task wfTask, ChangeType changeType) { + WorkItemEvent event = new WorkItemEvent(lightweightIdentifierGenerator, changeType, workItemType, wfTask.getWorkflowContext()); + fillInEvent(event, wfTask); return event; } } diff --git a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleWorkflowNotifier.java b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleWorkflowNotifier.java index 2f3a00f9c30..80c59e87d07 100644 --- a/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleWorkflowNotifier.java +++ b/model/notifications-impl/src/main/java/com/evolveum/midpoint/notifications/impl/notifiers/SimpleWorkflowNotifier.java @@ -103,11 +103,11 @@ protected String getBody(Event event, GeneralNotifierType generalNotifierType, S } body.append("Notification created on: ").append(new Date()).append("\n\n"); - if (techInfo) { - body.append("----------------------------------------\n"); - body.append("Technical information:\n\n"); - body.append(workflowEvent.getProcessInstanceState().debugDump()); - } +// if (techInfo) { +// body.append("----------------------------------------\n"); +// body.append("Technical information:\n\n"); +// body.append(workflowEvent.getProcessInstanceState().debugDump()); +// } return body.toString(); } diff --git a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/ProcessListener.java b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/ProcessListener.java index 01886bb6a49..45008d83034 100644 --- a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/ProcessListener.java +++ b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/ProcessListener.java @@ -16,9 +16,8 @@ package com.evolveum.midpoint.wf.api; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; +import com.evolveum.midpoint.task.api.Task; /** * An interface through which external observers can be notified about wf process related events. @@ -35,7 +34,7 @@ public interface ProcessListener { * @param instanceState externalized process instance variables * @param result implementer should report its result here */ - void onProcessInstanceStart(PrismObject instanceState, OperationResult result); + void onProcessInstanceStart(Task wfTask, OperationResult result); /** * This method is called by wf module when a process instance ends. @@ -43,5 +42,5 @@ public interface ProcessListener { * @param instanceState externalized process instance variables * @param result implementer should report its result here */ - void onProcessInstanceEnd(PrismObject instanceState, OperationResult result); + void onProcessInstanceEnd(Task wfTask, OperationResult result); } diff --git a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WfTaskExtensionItemsNames.java b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WfTaskExtensionItemsNames.java index a77d1283df0..fa4494b901d 100644 --- a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WfTaskExtensionItemsNames.java +++ b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WfTaskExtensionItemsNames.java @@ -29,29 +29,6 @@ public class WfTaskExtensionItemsNames { public static final String WORKFLOW_EXTENSION_NS = "http://midpoint.evolveum.com/model/workflow/extension-3"; - // Contains relevant activiti process instance ID (when known). - public static final QName WFPROCESSID_PROPERTY_NAME = new QName(WORKFLOW_EXTENSION_NS, "processInstanceId"); - - // Just a flag whether the process instance related to the task has already finished (used e.g. to determine if the shadowing handler should end or not). - public static final QName WFPROCESS_INSTANCE_FINISHED_PROPERTY_NAME = new QName(WORKFLOW_EXTENSION_NS, "processInstanceFinished"); - - // Contains name of class that manages this particular model operation ("change", thus "change processor"). - public static final QName WFCHANGE_PROCESSOR_PROPERTY_NAME = new QName(WORKFLOW_EXTENSION_NS, "changeProcessor"); - - // Contains history of process status messages. Such messages can contain any process-related messages that - // should be visible to the user (e.g. "your request was approved by engineering group, and is being sent - // to the management"). For simple processes, the status has mostly the value "Workflow process instance - // has proceeded". In order to be able to sort these status messages chronologically, each is prefixed - // by a timestamp (long value + formatted string value). Storing of these wfStatus values can be simply - // turned off in WfTaskUtil class. - public static final QName WFSTATUS_PROPERTY_NAME = new QName(WORKFLOW_EXTENSION_NS, "status"); - - // A dump of recent process instance variables (for diagnostic purposes). - public static final QName WFLAST_VARIABLES_PROPERTY_NAME = new QName(WORKFLOW_EXTENSION_NS, "lastVariables"); - - // String representation of recent process instance information (for diagnostic purposes). - public static final QName WFLAST_DETAILS_PROPERTY_NAME = new QName(WORKFLOW_EXTENSION_NS, "lastDetails"); - /** * This property is put into model task (i.e. not wf root task). It points to the * wf root task - that's important e.g. in cases when wf root task is not a subtask diff --git a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkItemListener.java b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkItemListener.java index f8acebbad52..64dc3131db7 100644 --- a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkItemListener.java +++ b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkItemListener.java @@ -16,8 +16,9 @@ package com.evolveum.midpoint.wf.api; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; /** * An interface through which external observers can be notified about work item related events. @@ -41,7 +42,7 @@ public interface WorkItemListener { * @param assigneeOid OID of the user to which the work item is assigned * @param instanceState externalized process instance state */ - public void onWorkItemCreation(String workItemName, String assigneeOid, PrismObject instanceState); + public void onWorkItemCreation(WorkItemType workItem, Task wfTask, OperationResult result); /** * This method is called by wf module when a work item is completed. @@ -51,5 +52,5 @@ public interface WorkItemListener { * @param instanceState externalized process instance state * @param decision decision of the user */ - public void onWorkItemCompletion(String workItemName, String assigneeOid, PrismObject instanceState, String decision); + public void onWorkItemCompletion(WorkItemType workItem, Task wfTask, OperationResult result); } diff --git a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkflowManager.java b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkflowManager.java index b95dc694c09..182440947be 100644 --- a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkflowManager.java +++ b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/api/WorkflowManager.java @@ -16,15 +16,19 @@ package com.evolveum.midpoint.wf.api; +import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessInstanceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; +import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import java.util.Collection; import java.util.List; @@ -42,64 +46,11 @@ public interface WorkflowManager { * ========== */ - /** - * Counts Work Items related to a user. - * - * @param userOid OID of the user - * @param assigned whether to count assigned (true) or assignable (false) work items - * @param parentResult - * @return number of relevant work items - * @throws WorkflowException - */ - int countWorkItemsRelatedToUser(String userOid, boolean assigned, OperationResult parentResult) throws SchemaException, ObjectNotFoundException; + Integer countContainers(Class type, ObjectQuery query, Collection> options, OperationResult result) + throws SchemaException; - /** - * Lists work items related to a user. - * - * @param userOid OID of the user - * @param assigned whether to count assigned (true) or assignable (false) work items - * @param first - * @param count - * @param parentResult - * @return list of work items - * @throws WorkflowException - */ - List listWorkItemsRelatedToUser(String userOid, boolean assigned, int first, int count, OperationResult parentResult) throws SchemaException, ObjectNotFoundException; - - /** - * Provides detailed information about a given work item (may be inefficient, so use with care). - * - * @param taskId - * @param parentResult - * @return - * @throws ObjectNotFoundException - * @throws WorkflowException - */ - WorkItemType getWorkItemDetailsById(String taskId, OperationResult parentResult) throws ObjectNotFoundException; - - /* - * Process instances - * ================= - */ - - int countProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, OperationResult parentResult); - - List listProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, int first, int count, OperationResult parentResult); - - WfProcessInstanceType getProcessInstanceByWorkItemId(String taskId, OperationResult parentResult) throws ObjectNotFoundException; - - /** - * Returns information about a process instance. WorkItems attribute is filled-in only upon request! (see getWorkItems parameter) - * - * @param instanceId - * @param historic - * @param getWorkItems - * @param parentResult - * @return - * @throws ObjectNotFoundException - * @throws WorkflowException - */ - public WfProcessInstanceType getProcessInstanceById(String instanceId, boolean historic, boolean getWorkItems, OperationResult parentResult) throws ObjectNotFoundException; + SearchResultList searchContainers(Class type, ObjectQuery query, Collection> options, OperationResult result) + throws SchemaException; /* * CHANGING THINGS @@ -108,20 +59,16 @@ public interface WorkflowManager { /** * Approves or rejects a work item (without supplying any further information). - * - * @param taskId identifier of activiti task backing the work item + * @param taskId identifier of activiti task backing the work item * @param decision true = approve, false = reject + * @param comment * @param parentResult */ - void approveOrRejectWorkItem(String taskId, boolean decision, OperationResult parentResult); - - void approveOrRejectWorkItemWithDetails(String taskId, PrismObject specific, boolean decision, OperationResult result); - - void completeWorkItemWithDetails(String taskId, PrismObject specific, String decision, OperationResult parentResult); + void approveOrRejectWorkItem(String taskId, boolean decision, String comment, OperationResult parentResult) throws SecurityViolationException; - void claimWorkItem(String workItemId, OperationResult result); + void claimWorkItem(String workItemId, OperationResult result) throws ObjectNotFoundException, SecurityViolationException; - void releaseWorkItem(String workItemId, OperationResult result); + void releaseWorkItem(String workItemId, OperationResult result) throws SecurityViolationException, ObjectNotFoundException; void stopProcessInstance(String instanceId, String username, OperationResult parentResult); @@ -146,4 +93,13 @@ public interface WorkflowManager { boolean isCurrentUserAuthorizedToSubmit(WorkItemType workItem); boolean isCurrentUserAuthorizedToClaim(WorkItemType workItem); + + // doesn't throw any exceptions - these are logged and stored into the operation result + void augmentTaskObject(PrismObject object, Collection> options, + Task task, OperationResult result); + + // doesn't throw any exceptions - these are logged and stored into the operation result + void augmentTaskObjectList(SearchResultList> list, + Collection> options, Task task, OperationResult result); + } diff --git a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/processors/primary/PcpTaskExtensionItemsNames.java b/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/processors/primary/PcpTaskExtensionItemsNames.java deleted file mode 100644 index b8a32945838..00000000000 --- a/model/workflow-api/src/main/java/com/evolveum/midpoint/wf/processors/primary/PcpTaskExtensionItemsNames.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2010-2014 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.processors.primary; - -import com.evolveum.midpoint.wf.api.WfTaskExtensionItemsNames; - -import javax.xml.namespace.QName; - -/** - * Names of workflow-related items that are stored in task extensions, - * specific to primary change processor. - * - * @author mederly - */ -public class PcpTaskExtensionItemsNames { - - // Contains deltaIn(i), i.e. delta(s) that has to be approved. - public static final QName WFDELTAS_TO_PROCESS_PROPERTY_NAME = new QName(WfTaskExtensionItemsNames.WORKFLOW_EXTENSION_NS, "deltasToProcess"); - - // Contains deltaOut(i), i.e. delta(s) that are the result of the approval process (most common situation is - // that deltaOut(i) = either deltaIn(i) (if approved), or null/empty delta (if rejected). - public static final QName WFRESULTING_DELTAS_PROPERTY_NAME = new QName(WfTaskExtensionItemsNames.WORKFLOW_EXTENSION_NS, "resultingDeltas"); - - // Contains a set of approvers who approved the delta(s). The change aspect should put here those approvers that - // will be stored into approvers list in metadata when the operation is really executed. - public static final QName WFAPPROVED_BY_REFERENCE_NAME = new QName(WfTaskExtensionItemsNames.WORKFLOW_EXTENSION_NS, "approvedBy"); - - // Name of class that provides an interface between midPoint and activiti process. - public static final QName WFPRIMARY_CHANGE_ASPECT_NAME = new QName(WfTaskExtensionItemsNames.WORKFLOW_EXTENSION_NS, "primaryChangeAspect"); -} diff --git a/model/workflow-impl/pom.xml b/model/workflow-impl/pom.xml index d9ba854ab2d..497193b5be7 100644 --- a/model/workflow-impl/pom.xml +++ b/model/workflow-impl/pom.xml @@ -85,6 +85,10 @@ org.activiti activiti-spring + + org.jetbrains + annotations-java5 + com.evolveum.midpoint.repo diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WfConfiguration.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WfConfiguration.java index a655db0fb5a..2d2ffd053a0 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WfConfiguration.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WfConfiguration.java @@ -24,12 +24,9 @@ import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.processors.BaseChangeProcessor; import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; - import org.apache.commons.configuration.Configuration; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.Validate; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -39,7 +36,6 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; - import java.util.*; /** @@ -71,7 +67,7 @@ public class WfConfiguration implements BeanFactoryAware { KEY_JDBC_USERNAME, KEY_JDBC_PASSWORD, KEY_DATA_SOURCE, KEY_ACTIVITI_SCHEMA_UPDATE, KEY_PROCESS_CHECK_INTERVAL, KEY_AUTO_DEPLOYMENT_FROM, KEY_ALLOW_APPROVE_OTHERS_ITEMS); - public static final List DEPRECATED_KEYS = Arrays.asList(CHANGE_PROCESSORS_SECTION); + public static final List DEPRECATED_KEYS = Collections.singletonList(CHANGE_PROCESSORS_SECTION); @Autowired private MidpointConfiguration midpointConfiguration; @@ -85,7 +81,7 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException { private static final String AUTO_DEPLOYMENT_FROM_DEFAULT = "classpath*:processes/*.bpmn20.xml"; - private Boolean enabled = null; + private boolean enabled; private boolean activitiSchemaUpdate; @@ -142,7 +138,7 @@ void initialize() { String explicitJdbcUrl = c.getString(KEY_JDBC_URL, null); if (explicitJdbcUrl == null) { - if (sqlConfig.isEmbedded()) { + if (sqlConfig == null || sqlConfig.isEmbedded()) { jdbcUrl = defaultJdbcUrlPrefix + "-activiti;DB_CLOSE_ON_EXIT=FALSE"; } else { jdbcUrl = sqlConfig.getJdbcUrl(); @@ -205,10 +201,10 @@ public void checkAllowedKeys(Configuration c, List knownKeys, List HookOperationMode invoke(ModelContext context, Task task, OperationResult parentResult) { Validate.notNull(context); Validate.notNull(task); @@ -152,20 +152,16 @@ HookOperationMode processModelInvocation(ModelContext cont for (ChangeProcessor changeProcessor : wfConfiguration.getChangeProcessors()) { if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Trying change processor: " + changeProcessor.getClass().getName()); + LOGGER.trace("Trying change processor: {}", changeProcessor.getClass().getName()); } try { HookOperationMode hookOperationMode = changeProcessor.processModelInvocation(context, wfConfigurationType, taskFromModel, result); if (hookOperationMode != null) { return hookOperationMode; } - } catch (SchemaException e) { - LoggingUtils.logException(LOGGER, "Schema exception while running change processor {}", e, changeProcessor.getClass().getName()); // todo message - result.recordFatalError("Schema exception while running change processor " + changeProcessor.getClass(), e); - return HookOperationMode.ERROR; - } catch (ObjectNotFoundException|RuntimeException e) { - LoggingUtils.logException(LOGGER, "Unexpected exception while running change processor {}", e, changeProcessor.getClass().getName()); // todo message - result.recordFatalError("Unexpected exception while running change processor " + changeProcessor.getClass(), e); + } catch (ObjectNotFoundException|SchemaException|RuntimeException e) { + LoggingUtils.logException(LOGGER, "Exception while running change processor {}", e, changeProcessor.getClass().getName()); // todo message + result.recordFatalError("Exception while running change processor " + changeProcessor.getClass(), e); return HookOperationMode.ERROR; } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WorkflowManagerImpl.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WorkflowManagerImpl.java index 06c8fb9beaf..a7375156f32 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WorkflowManagerImpl.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/WorkflowManagerImpl.java @@ -16,14 +16,18 @@ package com.evolveum.midpoint.wf.impl; +import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.query.ObjectQuery; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.util.exception.SecurityViolationException; import com.evolveum.midpoint.wf.api.ProcessListener; import com.evolveum.midpoint.wf.api.WorkItemListener; import com.evolveum.midpoint.wf.api.WorkflowManager; @@ -31,18 +35,17 @@ import com.evolveum.midpoint.wf.impl.activiti.dao.ProcessInstanceProvider; import com.evolveum.midpoint.wf.impl.activiti.dao.WorkItemManager; import com.evolveum.midpoint.wf.impl.activiti.dao.WorkItemProvider; -import com.evolveum.midpoint.wf.impl.jobs.JobController; -import com.evolveum.midpoint.wf.impl.jobs.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; import com.evolveum.midpoint.wf.util.ApprovalUtils; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessInstanceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; - import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; +import java.util.Collection; import java.util.List; /** @@ -51,15 +54,11 @@ @Component("workflowManager") public class WorkflowManagerImpl implements WorkflowManager { - private static final transient Trace LOGGER = TraceManager.getTrace(WorkflowManagerImpl.class); + //private static final transient Trace LOGGER = TraceManager.getTrace(WorkflowManagerImpl.class); @Autowired private PrismContext prismContext; - @Autowired - @Qualifier("cacheRepositoryService") - private com.evolveum.midpoint.repo.api.RepositoryService repositoryService; - @Autowired private WfConfiguration wfConfiguration; @@ -70,7 +69,7 @@ public class WorkflowManagerImpl implements WorkflowManager { private ProcessInstanceManager processInstanceManager; @Autowired - private JobController jobController; + private WfTaskController wfTaskController; @Autowired private WorkItemProvider workItemProvider; @@ -84,7 +83,7 @@ public class WorkflowManagerImpl implements WorkflowManager { @Autowired private MiscDataUtil miscDataUtil; - private static final String DOT_CLASS = WorkflowManagerImpl.class.getName() + "."; + private static final String DOT_INTERFACE = WorkflowManager.class.getName() + "."; /* @@ -93,42 +92,57 @@ public class WorkflowManagerImpl implements WorkflowManager { */ @Override - public int countWorkItemsRelatedToUser(String userOid, boolean assigned, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - return workItemProvider.countWorkItemsRelatedToUser(userOid, assigned, parentResult); - } - - @Override - public List listWorkItemsRelatedToUser(String userOid, boolean assigned, int first, int count, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - return workItemProvider.listWorkItemsRelatedToUser(userOid, assigned, first, count, parentResult); - } - - @Override - public WorkItemType getWorkItemDetailsById(String taskId, OperationResult parentResult) throws ObjectNotFoundException { - return workItemProvider.getWorkItemDetailsById(taskId, parentResult); - } - - @Override - public void approveOrRejectWorkItem(String taskId, boolean decision, OperationResult parentResult) { - workItemManager.completeWorkItemWithDetails(taskId, null, ApprovalUtils.approvalStringValue(decision), parentResult); - } - - @Override - public void approveOrRejectWorkItemWithDetails(String taskId, PrismObject specific, boolean decision, OperationResult parentResult) { - workItemManager.completeWorkItemWithDetails(taskId, specific, ApprovalUtils.approvalStringValue(decision), parentResult); - } - - @Override - public void completeWorkItemWithDetails(String taskId, PrismObject specific, String decision, OperationResult parentResult) { - workItemManager.completeWorkItemWithDetails(taskId, specific, decision, parentResult); - } - - @Override - public void claimWorkItem(String workItemId, OperationResult result) { + public Integer countContainers(Class type, ObjectQuery query, Collection> options, OperationResult parentResult) + throws SchemaException { + OperationResult result = parentResult.createSubresult(DOT_INTERFACE + ".countContainers"); + result.addParams(new String[] { "type", "query" }, type, query); + result.addCollectionOfSerializablesAsParam("options", options); + try { + if (!WorkItemType.class.equals(type)) { + throw new UnsupportedOperationException("countContainers is available only for work items"); + } + return workItemProvider.countWorkItems(query, options, result); + } catch (SchemaException|RuntimeException e) { + result.recordFatalError("Couldn't count items: " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); + } + } + + @SuppressWarnings("unchecked") + @Override + public SearchResultList searchContainers(Class type, ObjectQuery query, Collection> options, OperationResult parentResult) + throws SchemaException { + OperationResult result = parentResult.createSubresult(DOT_INTERFACE + ".searchContainers"); + result.addParams(new String[] { "type", "query" }, type, query); + result.addCollectionOfSerializablesAsParam("options", options); + try { + if (!WorkItemType.class.equals(type)) { + throw new UnsupportedOperationException("searchContainers is available only for work items"); + } + return (SearchResultList) workItemProvider.searchWorkItems(query, options, result); + } catch (SchemaException|RuntimeException e) { + result.recordFatalError("Couldn't count items: " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); + } + } + + @Override + public void approveOrRejectWorkItem(String taskId, boolean decision, String comment, OperationResult parentResult) + throws SecurityViolationException { + workItemManager.completeWorkItem(taskId, ApprovalUtils.approvalStringValue(decision), comment, parentResult); + } + + @Override + public void claimWorkItem(String workItemId, OperationResult result) throws ObjectNotFoundException, SecurityViolationException { workItemManager.claimWorkItem(workItemId, result); } @Override - public void releaseWorkItem(String workItemId, OperationResult result) { + public void releaseWorkItem(String workItemId, OperationResult result) throws SecurityViolationException, ObjectNotFoundException { workItemManager.releaseWorkItem(workItemId, result); } @@ -138,33 +152,30 @@ public void releaseWorkItem(String workItemId, OperationResult result) { */ @Override - public int countProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, OperationResult parentResult) { - return processInstanceProvider.countProcessInstancesRelatedToUser(userOid, requestedBy, requestedFor, finished, parentResult); - } - - @Override - public List listProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, int first, int count, OperationResult parentResult) { - return processInstanceProvider.listProcessInstancesRelatedToUser(userOid, requestedBy, requestedFor, finished, first, count, parentResult); + public void stopProcessInstance(String instanceId, String username, OperationResult parentResult) { + processInstanceManager.stopProcessInstance(instanceId, username, parentResult); } @Override - public WfProcessInstanceType getProcessInstanceByWorkItemId(String taskId, OperationResult parentResult) throws ObjectNotFoundException { - return processInstanceProvider.getProcessInstanceByTaskId(taskId, parentResult); + public void deleteProcessInstance(String instanceId, OperationResult parentResult) { + processInstanceManager.deleteProcessInstance(instanceId, parentResult); } - @Override - public WfProcessInstanceType getProcessInstanceById(String instanceId, boolean historic, boolean getWorkItems, OperationResult parentResult) throws ObjectNotFoundException { - return processInstanceProvider.getProcessInstanceByInstanceId(instanceId, historic, getWorkItems, parentResult); - } + /* + * Tasks + * ===== + */ @Override - public void stopProcessInstance(String instanceId, String username, OperationResult parentResult) { - processInstanceManager.stopProcessInstance(instanceId, username, parentResult); + public void augmentTaskObject(PrismObject object, + Collection> options, Task task, OperationResult result) { + processInstanceProvider.augmentTaskObject(object, options, task, result); } @Override - public void deleteProcessInstance(String instanceId, OperationResult parentResult) { - processInstanceManager.deleteProcessInstance(instanceId, parentResult); + public void augmentTaskObjectList(SearchResultList> list, + Collection> options, Task task, OperationResult result) { + processInstanceProvider.augmentTaskObjectList(list, options, task, result); } /* @@ -186,14 +197,18 @@ public WfTaskUtil getWfTaskUtil() { return wfTaskUtil; } + public MiscDataUtil getMiscDataUtil() { + return miscDataUtil; + } + @Override public void registerProcessListener(ProcessListener processListener) { - jobController.registerProcessListener(processListener); + wfTaskController.registerProcessListener(processListener); } @Override public void registerWorkItemListener(WorkItemListener workItemListener) { - jobController.registerWorkItemListener(workItemListener); + wfTaskController.registerWorkItemListener(workItemListener); } @Override diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiEngine.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiEngine.java index 0309b8f3854..e4cba69fe9a 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiEngine.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiEngine.java @@ -21,10 +21,8 @@ import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.impl.WfConfiguration; import com.evolveum.midpoint.wf.impl.activiti.users.MidPointUserManagerFactory; - import org.activiti.engine.*; import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; -import org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration; import org.activiti.engine.impl.history.HistoryLevel; import org.activiti.engine.impl.interceptor.SessionFactory; import org.activiti.engine.repository.Deployment; @@ -36,10 +34,11 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.xml.xpath.XPathExpressionException; - import java.io.IOException; import java.net.URL; -import java.util.*; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; /** * Manages Activiti instance (starts, stops, maintains reference to it). @@ -51,10 +50,7 @@ public class ActivitiEngine { private static final Trace LOGGER = TraceManager.getTrace(ActivitiEngine.class); - private static final String ADMINISTRATOR = "administrator"; - private ProcessEngine processEngine = null; - private static final String BPMN_URI = "http://www.omg.org/spec/BPMN/20100524/MODEL"; @Autowired private WfConfiguration wfConfiguration; @@ -62,25 +58,18 @@ public class ActivitiEngine { @PostConstruct public void init() { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Attempting to create Activiti engine."); - } - - if (wfConfiguration == null || wfConfiguration.isEnabled() == null) { - throw new IllegalStateException("WfConfiguration is not initialized, despite of ActivitiEngine depending on it - check Spring dependencies."); - } + LOGGER.trace("Attempting to create Activiti engine."); if (!wfConfiguration.isEnabled()) { LOGGER.trace("Workflows are disabled, exiting."); return; } - - List sessionFactories = new ArrayList(); + List sessionFactories = new ArrayList<>(); sessionFactories.add(new MidPointUserManagerFactory()); ProcessEngineConfiguration pec = - ((StandaloneProcessEngineConfiguration) ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration()) + ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration() .setDatabaseSchemaUpdate(wfConfiguration.isActivitiSchemaUpdate() ? ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE : ProcessEngineConfiguration.DB_SCHEMA_UPDATE_FALSE); @@ -106,31 +95,6 @@ public void init() { LOGGER.info("Activiti engine successfully created."); autoDeploy(); - -// IdentityService identityService = getIdentityService(); -// -// UserQuery uq = identityService.createUserQuery().userId(ADMINISTRATOR); -// if (uq.count() == 0) { -// User admin = identityService.newUser(ADMINISTRATOR); -// identityService.saveUser(admin); -// LOGGER.info("Created workflow user '" + ADMINISTRATOR + "'"); -// -// GroupQuery gq = identityService.createGroupQuery(); -// for (Group group : gq.list()) { -// identityService.createMembership(ADMINISTRATOR, group.getId()); -// LOGGER.info("Created membership of user '" + ADMINISTRATOR + "' in group '" + group.getId() + "'"); -// } -// -// LOGGER.info("Finished creating workflow user '" + ADMINISTRATOR + "' and its group membership."); -// } else { -// User admin = uq.singleResult(); -// LOGGER.info("User " + ADMINISTRATOR + " with ID " + admin.getId() + " exists."); -// List groups = identityService.createGroupQuery().groupMember(admin.getId()).list(); -// for (Group g : groups) { -// LOGGER.info(" - member of " + g.getId()); -// } -// -// } } private void autoDeploy() { @@ -151,14 +115,10 @@ private void autoDeploy() { for (Resource resource : resources) { try { autoDeployResource(resource); - } catch (IOException e) { - LoggingUtils.logException(LOGGER, "Couldn't deploy the resource " + resource, e); - } catch (XPathExpressionException e) { - LoggingUtils.logException(LOGGER, "Couldn't deploy the resource " + resource, e); - } catch (RuntimeException e) { + } catch (IOException | XPathExpressionException | RuntimeException e) { LoggingUtils.logException(LOGGER, "Couldn't deploy the resource " + resource, e); } - } + } } } @@ -186,7 +146,7 @@ private void autoDeployResource(Resource resource) throws IOException, XPathExpr } if (existing == null || tooOld) { - Deployment deployment = repositoryService.createDeployment().name(name).addInputStream(name, resource.getInputStream()).deploy(); + repositoryService.createDeployment().name(name).addInputStream(name, resource.getInputStream()).deploy(); LOGGER.info("Successfully deployed Activiti resource " + name); // + " as deployment with id = " + deployment.getId() + ", name = " + deployment.getName()); } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiEngineDataHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiEngineDataHelper.java deleted file mode 100644 index c687088a9f4..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiEngineDataHelper.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.activiti; - -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.api.WorkflowException; -import org.activiti.engine.ActivitiException; -import org.activiti.engine.HistoryService; -import org.activiti.engine.TaskService; -import org.activiti.engine.history.HistoricDetail; -import org.activiti.engine.history.HistoricDetailQuery; -import org.activiti.engine.history.HistoricVariableUpdate; -import org.activiti.engine.task.IdentityLink; -import org.activiti.engine.task.Task; -import org.activiti.engine.task.TaskQuery; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Auxiliary methods for accessing data in Activiti. - * - * @author mederly - */ - -@Component -public class ActivitiEngineDataHelper { - - private static final Trace LOGGER = TraceManager.getTrace(ActivitiEngineDataHelper.class); - - @Autowired - private ActivitiEngine activitiEngine; - - public Map getHistoricVariables(String pid, OperationResult result) throws WorkflowException { - - Map retval = new HashMap(); - - // copied from ActivitiInterface! - HistoryService hs = activitiEngine.getHistoryService(); - - try { - - HistoricDetailQuery hdq = hs.createHistoricDetailQuery() - .variableUpdates() - .processInstanceId(pid) - .orderByTime().desc(); - - for (HistoricDetail hd : hdq.list()) - { - HistoricVariableUpdate hvu = (HistoricVariableUpdate) hd; - String name = hvu.getVariableName(); - Object value = hvu.getValue(); - if (!retval.containsKey(name)) { - retval.put(name, value); - } - } - - return retval; - - } catch (ActivitiException e) { - String m = "Couldn't get variables for finished process instance " + pid; - result.recordFatalError(m, e); - throw new WorkflowException(m, e); - } - } - - public Map getProcessVariables(String taskId, OperationResult result) throws ObjectNotFoundException, WorkflowException { - try { - Task task = getTask(taskId); - Map variables = activitiEngine.getProcessEngine().getRuntimeService().getVariables((task.getExecutionId())); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Execution " + task.getExecutionId() + ", pid " + task.getProcessInstanceId() + ", variables = " + variables); - } - return variables; - } catch (ActivitiException e) { - String m = "Couldn't get variables for the process corresponding to task " + taskId; - result.recordFatalError(m, e); - throw new WorkflowException(m, e); - } - } - - // todo deduplicate this - // todo: ObjectNotFoundException used in unusual way (not in connection with midPoint repository) - private Task getTask(String taskId) throws ObjectNotFoundException { - Task task = activitiEngine.getTaskService().createTaskQuery().taskId(taskId).singleResult(); - if (task == null) { - throw new ObjectNotFoundException("Task " + taskId + " could not be found."); - } - return task; - } - - public Task getTaskById(String taskId, OperationResult result) throws ObjectNotFoundException { - TaskService taskService = activitiEngine.getTaskService(); - TaskQuery tq = taskService.createTaskQuery(); - tq.taskId(taskId); - Task task = tq.singleResult(); - if (task == null) { - result.recordFatalError("Task with ID " + taskId + " does not exist."); - throw new ObjectNotFoundException("Task with ID " + taskId + " does not exist."); - } else { - return task; - } - } - -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiInterface.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiInterface.java index a312a587328..c290e3a0b41 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiInterface.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/ActivitiInterface.java @@ -18,13 +18,17 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskExecutionStatus; import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.jobs.JobController; -import com.evolveum.midpoint.wf.impl.messages.ActivitiToMidPointMessage; -import com.evolveum.midpoint.wf.impl.messages.MidPointToActivitiMessage; +import com.evolveum.midpoint.wf.impl.activiti.dao.WorkItemProvider; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; import com.evolveum.midpoint.wf.impl.messages.ProcessFinishedEvent; import com.evolveum.midpoint.wf.impl.messages.ProcessStartedEvent; @@ -35,9 +39,9 @@ import com.evolveum.midpoint.wf.impl.messages.TaskCreatedEvent; import com.evolveum.midpoint.wf.impl.messages.TaskEvent; import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; -import com.evolveum.midpoint.wf.impl.processes.ProcessMidPointInterface; import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import org.activiti.engine.HistoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.delegate.DelegateExecution; @@ -49,6 +53,7 @@ import org.activiti.engine.history.HistoricVariableUpdate; import org.activiti.engine.impl.persistence.entity.ExecutionEntity; import org.activiti.engine.runtime.ProcessInstance; +import org.activiti.engine.runtime.ProcessInstanceBuilder; import org.activiti.engine.task.IdentityLink; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -73,197 +78,124 @@ public class ActivitiInterface { private TaskManager taskManager; @Autowired - private JobController jobController; + private WfTaskController wfTaskController; @Autowired private ProcessInterfaceFinder processInterfaceFinder; - /** - * Processes a message coming from midPoint to activiti. Although currently activiti is co-located with midPoint, - * the interface between them is designed to be more universal - based on message passing. - * - * We pass task and operation result objects here. It is just because it is convenient for us and we CAN do this - * (because of co-location of activiti and midPoint). In remote versions we will eliminate this. The code - * is written in such a way that this should not pose a problem. - */ - - public void midpoint2activiti(MidPointToActivitiMessage cmd, Task task, OperationResult result) { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(" *** A command from midPoint has arrived; class = " + cmd.getClass().getName() + " ***"); - } - - if (cmd instanceof QueryProcessCommand) - { - QueryProcessCommand qpc = (QueryProcessCommand) cmd; - QueryProcessResponse qpr = new QueryProcessResponse(); - - String pid = qpc.getPid(); - qpr.setPid(pid); - qpr.setTaskOid(qpc.getTaskOid()); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Querying process instance id = " + pid); - } - - HistoryService hs = activitiEngine.getHistoryService(); - - HistoricDetailQuery hdq = hs.createHistoricDetailQuery() - .variableUpdates() - .processInstanceId(pid) - .orderByTime().desc(); - - for (HistoricDetail hd : hdq.list()) - { - HistoricVariableUpdate hvu = (HistoricVariableUpdate) hd; - String varname = hvu.getVariableName(); - Object value = hvu.getValue(); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(" - found historic variable update: " + varname + " <- " + value); - } - if (!qpr.containsVariable(varname)) { - qpr.putVariable(varname, value); - } - } - - HistoricDetailQuery hdq2 = hs.createHistoricDetailQuery() - .formProperties() - .processInstanceId(pid) - .orderByVariableRevision().desc(); - for (HistoricDetail hd : hdq2.list()) - { - HistoricFormProperty hfp = (HistoricFormProperty) hd; - String varname = hfp.getPropertyId(); - Object value = hfp.getPropertyValue(); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace(" - found historic form property: " + varname + " <- " + value); - } - qpr.putVariable(varname, value); - } - - ProcessInstance pi = activitiEngine.getProcessEngine().getRuntimeService().createProcessInstanceQuery().processInstanceId(pid).singleResult(); - qpr.setRunning(pi != null && !pi.isEnded()); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Running process instance = " + pi + ", isRunning: " + qpr.isRunning()); - LOGGER.trace("Response to be sent to midPoint: " + qpr); - } - fillInAnswerAndState(qpr); - - activiti2midpoint(qpr, task, false, result); - } - else if (cmd instanceof StartProcessCommand) - { - StartProcessCommand spic = (StartProcessCommand) cmd; - - Map map = new HashMap(); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("midpointTaskOid = " + spic.getTaskOid()); - } - - map.put(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID, spic.getTaskOid()); - map.putAll(spic.getVariables()); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("process name = " + spic.getProcessName()); - } - - RuntimeService rs = activitiEngine.getProcessEngine().getRuntimeService(); - - String owner = ((StartProcessCommand) cmd).getProcessOwner(); - if (owner != null) { - activitiEngine.getIdentityService().setAuthenticatedUserId(owner); - } - //String businessKey = (String) map.get(WfConstants.VARIABLE_MIDPOINT_OBJECT_OID); - //ProcessInstance pi = rs.startProcessInstanceByKey(spic.getProcessDefinitionKey(), businessKey, map); - ProcessInstance pi = rs.startProcessInstanceByKey(spic.getProcessName(), map); - - // let us send a reply back (useful for listener-free processes) - - if (spic.isSendStartConfirmation()) { - ProcessStartedEvent event = new ProcessStartedEvent(); - event.setTaskOid(spic.getTaskOid()); - event.setPid(pi.getProcessInstanceId()); - event.setVariablesFrom(((ExecutionEntity) pi).getVariables()); // a bit of hack... - event.setRunning(!pi.isEnded()); - fillInAnswerAndState(event); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Event to be sent to IDM: " + event); - } - activiti2midpoint(event, task, false, result); - } - } - else - { - String message = "Unknown incoming message type: " + cmd.getClass().getName(); - LOGGER.error(message); - } - } - - // task and parentResult may be null e.g. if this method is called from activiti process (for "smart" processes) - // asynchronous = true if this method is called from activiti process ("smart" processes), false if it is called as a response - // to either query (from periodic querying of dumb processes) or to process start instruction - // asynchronous messages are accepted only if task state is WAITING, in order to eliminate duplicate processing of finish messages - public void activiti2midpoint(ActivitiToMidPointMessage msg, Task task, boolean asynchronous, OperationResult parentResult) { - - OperationResult result; - if (parentResult == null) { - result = new OperationResult(DOT_CLASS + "activiti2midpoint"); - } else { - result = parentResult.createSubresult(DOT_CLASS + "activiti2midpoint"); - } - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("activiti2midpoint starting."); - } - - try { - jobController.processWorkflowMessage(msg, task, asynchronous, result); - } catch (Exception e) { // todo fix the exception processing - String message = "Couldn't process an event coming from the workflow management system"; - LoggingUtils.logException(LOGGER, message, e); - result.recordFatalError(message, e); - } - - if (result.isUnknown()) { - result.computeStatus(); - } - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("activiti2midpoint ending; operation result status = " + result.getStatus()); - } - } - - public void notifyMidpointAboutProcessFinishedEvent(DelegateExecution execution) { - notifyMidpointAboutProcessEvent(execution, new ProcessFinishedEvent()); + @Autowired + private WorkItemProvider workItemProvider; + + public void startActivitiProcessInstance(StartProcessCommand spic, Task task, OperationResult result) + throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { + + String owner = spic.getProcessOwner(); + if (owner != null) { + activitiEngine.getIdentityService().setAuthenticatedUserId(owner); + } + + RuntimeService rs = activitiEngine.getProcessEngine().getRuntimeService(); + ProcessInstanceBuilder builder = rs.createProcessInstanceBuilder() + .processDefinitionKey(spic.getProcessName()) + .processInstanceName(spic.getProcessInstanceName()); + for (Map.Entry varEntry : spic.getVariables().entrySet()) { + builder.addVariable(varEntry.getKey(), varEntry.getValue()); + } + ProcessInstance pi = builder.start(); + + if (spic.isSendStartConfirmation()) { // let us send a reply back (useful for listener-free processes) + ProcessStartedEvent event = new ProcessStartedEvent( + pi.getProcessInstanceId(), + ((ExecutionEntity) pi).getVariables(), // a bit of hack... + processInterfaceFinder); + event.setRunning(!pi.isEnded()); + LOGGER.trace("Event to be sent to IDM: {}", event); + wfTaskController.onProcessEvent(event, task, result); + } + } + + public void queryActivitiProcessInstance(QueryProcessCommand qpc, Task task, OperationResult result) + throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { + + String pid = qpc.getPid(); + LOGGER.trace("Querying process instance id {}", pid); + + HistoryService hs = activitiEngine.getHistoryService(); + + HistoricDetailQuery hdq = hs.createHistoricDetailQuery() + .variableUpdates() + .processInstanceId(pid) + .orderByTime().desc(); + + Map variables = new HashMap<>(); + for (HistoricDetail hd : hdq.list()) { + HistoricVariableUpdate hvu = (HistoricVariableUpdate) hd; + String varname = hvu.getVariableName(); + Object value = hvu.getValue(); + LOGGER.trace(" - found historic variable update: {} <- {}", varname, value); + if (!variables.containsKey(varname)) { + variables.put(varname, value); + } + } + + HistoricDetailQuery hdq2 = hs.createHistoricDetailQuery() + .formProperties() + .processInstanceId(pid) + .orderByVariableRevision().desc(); + for (HistoricDetail hd : hdq2.list()) { + HistoricFormProperty hfp = (HistoricFormProperty) hd; + String varname = hfp.getPropertyId(); + Object value = hfp.getPropertyValue(); + LOGGER.trace(" - found historic form property: {} <- {}", varname, value); + variables.put(varname, value); + } + + QueryProcessResponse qpr = new QueryProcessResponse(pid, variables, processInterfaceFinder); + + ProcessInstance pi = activitiEngine.getProcessEngine().getRuntimeService().createProcessInstanceQuery().processInstanceId(pid).singleResult(); + qpr.setRunning(pi != null && !pi.isEnded()); + LOGGER.trace("Running process instance = {}, isRunning: {}", pi, qpr.isRunning()); + LOGGER.trace("Response to be sent to midPoint: {}", qpr); + + wfTaskController.onProcessEvent(qpr, task, result); + } + + public void notifyMidpointAboutProcessFinishedEvent(DelegateExecution execution) { + notifyMidpointAboutProcessEvent(new ProcessFinishedEvent(execution, processInterfaceFinder)); } public void notifyMidpointAboutProcessEvent(DelegateExecution execution) { - notifyMidpointAboutProcessEvent(execution, new ProcessEvent()); - } - - public void notifyMidpointAboutProcessEvent(DelegateExecution execution, ProcessEvent event) { - event.setPid(execution.getProcessInstanceId()); - event.setRunning(true); - event.setTaskOid((String) execution.getVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID)); - event.setVariablesFrom(execution.getVariables()); - fillInAnswerAndState(event); - activiti2midpoint(event, null, true, new OperationResult(DOT_CLASS + "notifyMidpointAboutProcessEvent")); + notifyMidpointAboutProcessEvent(new ProcessEvent(execution, processInterfaceFinder)); } - private void fillInAnswerAndState(ProcessEvent event) { - ProcessMidPointInterface processInterface = processInterfaceFinder.getProcessInterface(event.getVariables()); - event.setAnswer(processInterface.getAnswer(event.getVariables())); - event.setState(processInterface.getState(event.getVariables())); + private void notifyMidpointAboutProcessEvent(ProcessEvent event) { + OperationResult result = new OperationResult(DOT_CLASS + "notifyMidpointAboutProcessEvent"); + + String taskOid = event.getVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID, String.class); + if (taskOid == null) { + throw new IllegalStateException("No task OID in process variables for " + event.getProcessDebugInfo()); + } + Task task; + try { + task = taskManager.getTask(taskOid, result); + } catch (ObjectNotFoundException|SchemaException|RuntimeException e) { + throw new SystemException("Couldn't get task " + taskOid + " from repository: " + e.getMessage(), e); + } + if (task.getExecutionStatus() != TaskExecutionStatus.WAITING) { + LOGGER.trace("Asynchronous message received in a state different from WAITING (actual state: {}), ignoring it. Task = {}", task.getExecutionStatus(), task); + return; + } + try { + wfTaskController.onProcessEvent(event, task, result); + } catch (SchemaException|ObjectNotFoundException|ObjectAlreadyExistsException|RuntimeException e) { + throw new SystemException("Couldn't process a process-related event: " + e.getMessage(), e); + } } - //region Processing work item events - public void notifyMidpointAboutTaskEvent(DelegateTask delegateTask) { - OperationResult result = new OperationResult(DOT_CLASS + "notifyMidpointAboutTaskEvent"); - TaskEvent taskEvent = new TaskEvent(); + TaskEvent taskEvent; if (TaskListener.EVENTNAME_CREATE.equals(delegateTask.getEventName())) { taskEvent = new TaskCreatedEvent(); } else if (TaskListener.EVENTNAME_COMPLETE.equals(delegateTask.getEventName())) { @@ -292,13 +224,12 @@ public void notifyMidpointAboutTaskEvent(DelegateTask delegateTask) { } try { - jobController.processWorkflowMessage(taskEvent, null, true, result); + WorkItemType workItem = workItemProvider.taskEventToWorkItemNew(taskEvent, null, true, true, true, result); + wfTaskController.onTaskEvent(workItem, taskEvent, result); } catch (Exception e) { // todo fix the exception processing e.g. think about situation where an event cannot be audited - should we allow to proceed? String message = "Couldn't process an event coming from the workflow management system"; LoggingUtils.logException(LOGGER, message, e); result.recordFatalError(message, e); } } - - //endregion } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/ProcessInstanceManager.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/ProcessInstanceManager.java index 04bafa322df..a95436ca370 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/ProcessInstanceManager.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/ProcessInstanceManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2013 Evolveum + * Copyright (c) 2010-2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,11 +21,8 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.api.WorkflowManager; -import com.evolveum.midpoint.wf.impl.WorkflowManagerImpl; import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine; import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; - -import org.activiti.engine.ActivitiException; import org.activiti.engine.HistoryService; import org.activiti.engine.RuntimeService; import org.springframework.beans.factory.annotation.Autowired; @@ -43,7 +40,6 @@ public class ProcessInstanceManager { @Autowired private ActivitiEngine activitiEngine; - private static final String DOT_CLASS = WorkflowManagerImpl.class.getName() + "."; private static final String DOT_INTERFACE = WorkflowManager.class.getName() + "."; private static final String OPERATION_STOP_PROCESS_INSTANCE = DOT_INTERFACE + "stopProcessInstance"; @@ -57,13 +53,13 @@ public void stopProcessInstance(String instanceId, String username, OperationRes try { LOGGER.trace("Stopping process instance {} on the request of {}", instanceId, username); String deletionMessage = "Process instance stopped on the request of " + username; -// rs.setVariable(instanceId, CommonProcessVariableNames.VARIABLE_WF_STATE, deletionMessage); - rs.setVariable(instanceId, CommonProcessVariableNames.VARIABLE_MIDPOINT_IS_PROCESS_INSTANCE_STOPPING, Boolean.TRUE); + rs.setVariable(instanceId, CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_IS_STOPPING, Boolean.TRUE); rs.deleteProcessInstance(instanceId, deletionMessage); - result.recordSuccess(); - } catch (ActivitiException e) { - result.recordFatalError("Process instance couldn't be stopped", e); - LoggingUtils.logException(LOGGER, "Process instance {} couldn't be stopped", e, instanceId); + } catch (RuntimeException e) { + result.recordFatalError("Process instance couldn't be stopped: " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); } } @@ -74,11 +70,12 @@ public void deleteProcessInstance(String instanceId, OperationResult parentResul HistoryService hs = activitiEngine.getHistoryService(); try { hs.deleteHistoricProcessInstance(instanceId); - result.recordSuccess(); - } catch (ActivitiException e) { + } catch (RuntimeException e) { result.recordFatalError("Process instance couldn't be deleted", e); - LoggingUtils.logException(LOGGER, "Process instance {} couldn't be deleted", e); - } + throw e; + } finally { + result.computeStatusIfUnknown(); + } } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/ProcessInstanceProvider.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/ProcessInstanceProvider.java index e64d6b10403..f726d599900 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/ProcessInstanceProvider.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/ProcessInstanceProvider.java @@ -16,39 +16,29 @@ package com.evolveum.midpoint.wf.impl.activiti.dao; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.WfConfiguration; -import com.evolveum.midpoint.wf.impl.WorkflowManagerImpl; -import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine; -import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngineDataHelper; - -import com.evolveum.midpoint.wf.api.WorkflowException; import com.evolveum.midpoint.wf.api.WorkflowManager; -import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessInstanceType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; -import org.activiti.engine.ActivitiException; -import org.activiti.engine.HistoryService; -import org.activiti.engine.RuntimeService; -import org.activiti.engine.TaskService; -import org.activiti.engine.history.HistoricProcessInstance; -import org.activiti.engine.history.HistoricProcessInstanceQuery; -import org.activiti.engine.query.Query; -import org.activiti.engine.runtime.ProcessInstanceQuery; -import org.activiti.engine.task.Task; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.xml.bind.JAXBException; -import java.util.*; +import java.util.Collection; +import java.util.List; + +import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_WORKFLOW_CONTEXT; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType.F_WORK_ITEM; /** * @author mederly @@ -58,248 +48,58 @@ public class ProcessInstanceProvider { private static final transient Trace LOGGER = TraceManager.getTrace(ProcessInstanceProvider.class); - @Autowired - private ActivitiEngine activitiEngine; - - @Autowired - private ActivitiEngineDataHelper activitiEngineDataHelper; - @Autowired private WorkItemProvider workItemProvider; - @Autowired - private WfConfiguration wfConfiguration; - - private static final String DOT_CLASS = WorkflowManagerImpl.class.getName() + "."; private static final String DOT_INTERFACE = WorkflowManager.class.getName() + "."; + private static final String OPERATION_AUGMENT_TASK_OBJECT = DOT_INTERFACE + "augmentTaskObject"; - private static final String OPERATION_COUNT_PROCESS_INSTANCES_RELATED_TO_USER = DOT_INTERFACE + "countProcessInstancesRelatedToUser"; - private static final String OPERATION_LIST_PROCESS_INSTANCES_RELATED_TO_USER = DOT_INTERFACE + "listProcessInstancesRelatedToUser"; - private static final String OPERATION_GET_PROCESS_INSTANCE_BY_TASK_ID = DOT_INTERFACE + "getProcessInstanceByWorkItemId"; - private static final String OPERATION_GET_PROCESS_INSTANCE_BY_INSTANCE_ID = DOT_INTERFACE + "getProcessInstanceById"; - private static final String OPERATION_ACTIVITI_TO_MIDPOINT_PROCESS_INSTANCE = DOT_CLASS + "activitiToMidpointRunningProcessInstance"; - private static final String OPERATION_ACTIVITI_TO_MIDPOINT_PROCESS_INSTANCE_HISTORY = DOT_CLASS + "activitiToMidpointProcessInstanceHistory"; + // doesn't throw any exceptions - these are logged and stored into the operation result + public void augmentTaskObject(PrismObject object, + Collection> options, Task opTask, OperationResult parentResult) { - /* - * ========================= PART 1 - main operations ========================= - */ + final OperationResult result = parentResult.createSubresult(OPERATION_AUGMENT_TASK_OBJECT); + result.addParam("object", ObjectTypeUtil.toShortString(object)); + result.addCollectionOfSerializablesAsParam("options", options); - public int countProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, OperationResult parentResult) { - OperationResult result = parentResult.createSubresult(OPERATION_COUNT_PROCESS_INSTANCES_RELATED_TO_USER); - result.addParam("userOid", userOid); - result.addParam("requestedBy", requestedBy); - result.addParam("requestedFor", requestedFor); - result.addParam("finished", finished); - try { - int instances = (int) createQueryForProcessInstancesRelatedToUser(userOid, requestedBy, requestedFor, finished).count(); - result.recordSuccessIfUnknown(); - return instances; - } catch (ActivitiException e) { - String m = "Couldn't count process instances related to " + userOid + " due to Activiti exception"; - result.recordFatalError(m, e); - throw new SystemException(m, e); + if (!(object.asObjectable() instanceof TaskType)) { + result.recordNotApplicableIfUnknown(); + return; } - } + final TaskType taskType = (TaskType) object.asObjectable(); - public List listProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished, int first, int count, OperationResult parentResult) { - OperationResult result = parentResult.createSubresult(OPERATION_LIST_PROCESS_INSTANCES_RELATED_TO_USER); - result.addParam("userOid", userOid); - result.addParam("requestedBy", requestedBy); - result.addParam("requestedFor", requestedFor); - result.addParam("finished", finished); - result.addParam("first", first); - result.addParam("count", count); try { - List instances = createQueryForProcessInstancesRelatedToUser(userOid, requestedBy, requestedFor, finished).listPage(first, count); - List mInstances = finished ? - activitiToMidpointHistoricProcessInstanceList((List) instances, result) : - activitiToMidpointRunningProcessInstanceList((List) instances, false, result); // false = no work items - result.recordSuccessIfUnknown(); - return mInstances; - } catch (ActivitiException e) { - String m = "Couldn't list process instances related to " + userOid + " due to Activiti exception"; - result.recordFatalError(m, e); - throw new SystemException(m, e); - } - } - - private Query createQueryForProcessInstancesRelatedToUser(String userOid, boolean requestedBy, boolean requestedFor, boolean finished) { - if (finished) { - HistoryService hs = activitiEngine.getHistoryService(); - - HistoricProcessInstanceQuery hpiq = hs.createHistoricProcessInstanceQuery().finished().orderByProcessInstanceEndTime().desc(); - if (requestedBy) { - hpiq = hpiq.startedBy(userOid); - } - if (requestedFor) { - hpiq = hpiq.variableValueEquals(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID, userOid); - } - return hpiq; - } else { - ProcessInstanceQuery piq = activitiEngine.getRuntimeService().createProcessInstanceQuery().orderByProcessInstanceId().asc(); - if (requestedBy) { - piq = piq.variableValueEquals(CommonProcessVariableNames.VARIABLE_MIDPOINT_REQUESTER_OID, userOid); - } - if (requestedFor) { - piq = piq.variableValueEquals(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID, userOid); - } - return piq; - } - } - - public WfProcessInstanceType getProcessInstanceByTaskId(String taskId, OperationResult parentResult) throws ObjectNotFoundException { - OperationResult result = parentResult.createSubresult(OPERATION_GET_PROCESS_INSTANCE_BY_TASK_ID); - result.addParam("taskId", taskId); - Task task = activitiEngineDataHelper.getTaskById(taskId, result); - return getProcessInstanceByInstanceIdInternal(task.getProcessInstanceId(), false, true, result); // true = load also work items - } - - public WfProcessInstanceType getProcessInstanceByInstanceId(String instanceId, boolean historic, boolean getWorkItems, OperationResult parentResult) throws ObjectNotFoundException { - OperationResult result = parentResult.createSubresult(OPERATION_GET_PROCESS_INSTANCE_BY_INSTANCE_ID); - result.addParam("instanceId", instanceId); - result.addParam("historic", historic); - return getProcessInstanceByInstanceIdInternal(instanceId, historic, getWorkItems, result); - } - - private WfProcessInstanceType getProcessInstanceByInstanceIdInternal(String instanceId, boolean historic, boolean getWorkItems, OperationResult result) throws ObjectNotFoundException { - - if (historic) { - HistoricProcessInstanceQuery hpiq = activitiEngine.getHistoryService().createHistoricProcessInstanceQuery(); - hpiq.processInstanceId(instanceId); - HistoricProcessInstance historicProcessInstance = hpiq.singleResult(); - if (historicProcessInstance != null) { - WfProcessInstanceType retval = activitiToMidpointProcessInstanceHistory(historicProcessInstance, result); - result.computeStatus(); - return retval; - } else { - result.recordFatalError("Process instance " + instanceId + " couldn't be found."); - throw new ObjectNotFoundException("Process instance " + instanceId + " couldn't be found."); - } - } else { - ProcessInstanceQuery piq = activitiEngine.getRuntimeService().createProcessInstanceQuery(); - piq.processInstanceId(instanceId); - org.activiti.engine.runtime.ProcessInstance instance = piq.singleResult(); - - if (instance != null) { - WfProcessInstanceType retval = activitiToMidpointRunningProcessInstance(instance, getWorkItems, result); - result.computeStatus(); - return retval; - } else { - result.recordFatalError("Process instance " + instanceId + " couldn't be found."); - throw new ObjectNotFoundException("Process instance " + instanceId + " couldn't be found."); + if (taskType.getWorkflowContext() == null) { + return; } - } - } - - /* - * ========================= PART 2 - activiti to midpoint converters ========================= - * - * getWorkItems parameter influences whether we want to get also work items for the particular process instance - * (may be quite slow to execute). - * - */ - - private List activitiToMidpointRunningProcessInstanceList(List instances, boolean getWorkItems, OperationResult result) { - List retval = new ArrayList(); - int problems = 0; - Exception lastException = null; - for (org.activiti.engine.runtime.ProcessInstance instance : instances) { - try { - retval.add(activitiToMidpointRunningProcessInstance(instance, getWorkItems, result)); - } catch(Exception e) { // todo: was WorkflowException - problems++; - lastException = e; - // this is a design decision: when an error occurs when listing instances, the ones that are fine WILL BE displayed - LoggingUtils.logException(LOGGER, "Couldn't get information on workflow process instance", e); - // operation result already contains the exception information + final String instanceId = taskType.getWorkflowContext().getProcessInstanceId(); + if (instanceId == null) { + return; } - } - if (problems > 0) { - result.recordWarning(problems + " active instance(s) could not be shown; last exception: " + lastException.getMessage(), lastException); - } - return retval; - } - - private List activitiToMidpointHistoricProcessInstanceList(List instances, OperationResult result) { - List retval = new ArrayList(); - for (HistoricProcessInstance instance : instances) { - retval.add(activitiToMidpointProcessInstanceHistory(instance, result)); - if (!result.getLastSubresult().isSuccess()) { - // this is a design decision: when an error occurs when listing instances, the ones that are fine WILL BE displayed - LOGGER.error("Couldn't get information on workflow process instance", result.getLastSubresult().getMessage()); - // operation result already contains the exception information + final boolean retrieveWorkItems = SelectorOptions.hasToLoadPath(new ItemPath(F_WORKFLOW_CONTEXT, F_WORK_ITEM), options); + if (!retrieveWorkItems) { + // We assume that everything (except work items) is already stored in repo. + return; } + final List workItems = workItemProvider.getWorkItemsForProcessInstanceId(instanceId, result); + taskType.getWorkflowContext().getWorkItem().addAll(workItems); + } catch (RuntimeException e) { + result.recordFatalError(e.getMessage(), e); + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't prepare wf-related information for {}", e, ObjectTypeUtil.toShortString(object)); + } finally { + result.computeStatusIfUnknown(); } - result.computeStatusIfUnknown(); - return retval; - } - - private WfProcessInstanceType activitiToMidpointRunningProcessInstance(org.activiti.engine.runtime.ProcessInstance instance, boolean getWorkItems, OperationResult parentResult) { - - OperationResult result = parentResult.createSubresult(OPERATION_ACTIVITI_TO_MIDPOINT_PROCESS_INSTANCE); - result.addParam("instance id", instance.getProcessInstanceId()); - result.addParam("getWorkItems", getWorkItems); - - WfProcessInstanceType pi = new WfProcessInstanceType(); - pi.setFinished(false); - pi.setProcessInstanceId(instance.getProcessInstanceId()); - - RuntimeService rs = activitiEngine.getRuntimeService(); - - Map vars = null; - try { - vars = rs.getVariables(instance.getProcessInstanceId()); - } catch (ActivitiException e) { - result.recordFatalError("Couldn't get process instance variables for instance " + instance.getProcessInstanceId(), e); - LoggingUtils.logException(LOGGER, "Couldn't get process instance variables for instance {}", e, instance.getProcessInstanceId()); - pi.setName(new PolyStringType("(unreadable process instance with id = " + instance.getId() + ")")); - pi.setStartTimestamp(null); - return pi; - } - - ChangeProcessor cp = wfConfiguration.findChangeProcessor((String) vars.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR)); - - try { - pi.setState(cp.externalizeProcessInstanceState(vars).asObjectable()); - } catch (JAXBException|SchemaException e) { - result.recordFatalError("Couldn't externalize process instance state for instance " + instance.getProcessInstanceId(), e); - LoggingUtils.logException(LOGGER, "Couldn't externalize process instance state for instance {}", e, instance.getProcessInstanceId()); - } - - pi.setName(new PolyStringType((String) vars.get(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME))); - pi.setStartTimestamp(XmlTypeConverter.createXMLGregorianCalendar((Date) vars.get(CommonProcessVariableNames.VARIABLE_START_TIME))); - - if (getWorkItems) { - TaskService ts = activitiEngine.getTaskService(); - List tasks = ts.createTaskQuery().processInstanceId(instance.getProcessInstanceId()).list(); - pi.getWorkItems().addAll(workItemProvider.tasksToWorkItems(tasks, false, true, true, result)); // "no" to task forms, "yes" to assignee and candidate details - } - - result.recordSuccessIfUnknown(); - return pi; - } - public WfProcessInstanceType activitiToMidpointProcessInstanceHistory(HistoricProcessInstance instance, OperationResult parentResult) { + if (!result.isSuccess()) { + taskType.setFetchResult(result.createOperationResultType()); + } + } - OperationResult result = parentResult.createSubresult(OPERATION_ACTIVITI_TO_MIDPOINT_PROCESS_INSTANCE_HISTORY); - - WfProcessInstanceType pi = new WfProcessInstanceType(); - pi.setFinished(true); - pi.setProcessInstanceId(instance.getId()); - pi.setStartTimestamp(XmlTypeConverter.createXMLGregorianCalendar(instance.getStartTime())); - pi.setEndTimestamp(XmlTypeConverter.createXMLGregorianCalendar(instance.getEndTime())); - - try { - Map vars = activitiEngineDataHelper.getHistoricVariables(instance.getId(), result); - pi.setName(new PolyStringType((String) vars.get(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME))); - ChangeProcessor cp = wfConfiguration.findChangeProcessor((String) vars.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR)); - pi.setState(cp.externalizeProcessInstanceState(vars).asObjectable()); - result.recordSuccessIfUnknown(); - return pi; - } catch (RuntimeException|WorkflowException|JAXBException|SchemaException e) { - result.recordFatalError("Couldn't get information about finished process instance " + instance.getId(), e); - pi.setName(new PolyStringType("(unreadable process instance with id = " + instance.getId() + ")")); - return pi; + // doesn't throw any exceptions - these are logged and stored into the operation result + public void augmentTaskObjectList(SearchResultList> list, + Collection> options, com.evolveum.midpoint.task.api.Task task, OperationResult result) { + for (PrismObject object : list) { + augmentTaskObject(object, options, task, result); } } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/WorkItemManager.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/WorkItemManager.java index b00919b9034..53811d215b4 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/WorkItemManager.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/WorkItemManager.java @@ -16,22 +16,18 @@ package com.evolveum.midpoint.wf.impl.activiti.dao; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.SecurityEnforcer; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SecurityViolationException; +import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.api.WorkflowManager; -import com.evolveum.midpoint.wf.impl.WorkflowManagerImpl; import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine; import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; - -import org.activiti.engine.ActivitiException; -import org.activiti.engine.ActivitiObjectNotFoundException; import org.activiti.engine.FormService; import org.activiti.engine.TaskService; import org.activiti.engine.form.FormProperty; @@ -42,12 +38,11 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.xml.namespace.QName; - import java.util.HashMap; -import java.util.List; import java.util.Map; +import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.toShortString; + /** * @author mederly */ @@ -66,183 +61,108 @@ public class WorkItemManager { @Autowired private SecurityEnforcer securityEnforcer; - private static final String DOT_CLASS = WorkflowManagerImpl.class.getName() + "."; private static final String DOT_INTERFACE = WorkflowManager.class.getName() + "."; - private static final String OPERATION_COMPLETE_WORK_ITEM = DOT_CLASS + "completeWorkItemWithDetails"; - private static final String OPERATION_CLAIM_WORK_ITEM = DOT_CLASS + "claimWorkItem"; - private static final String OPERATION_RELEASE_WORK_ITEM = DOT_CLASS + "releaseWorkItem"; + private static final String OPERATION_COMPLETE_WORK_ITEM = DOT_INTERFACE + "completeWorkItem"; + private static final String OPERATION_CLAIM_WORK_ITEM = DOT_INTERFACE + "claimWorkItem"; + private static final String OPERATION_RELEASE_WORK_ITEM = DOT_INTERFACE + "releaseWorkItem"; - // choiceDecision - contains the name of the button ([B]xxxx) that was pressed - // approvalDecision - contains true or false (approved / rejected) - // - // exactly one of choiceDecision and approvalDecision must be set - // - // todo error reporting - public void completeWorkItemWithDetails(String taskId, PrismObject specific, String decision, OperationResult parentResult) { - - MidPointPrincipal principal; - try { - principal = securityEnforcer.getPrincipal(); - } catch (SecurityViolationException e) { - LOGGER.error("Security violation: {}", e.getMessage(), e); - return; - } + public void completeWorkItem(String taskId, String decision, String comment, OperationResult parentResult) throws SecurityViolationException { OperationResult result = parentResult.createSubresult(OPERATION_COMPLETE_WORK_ITEM); - result.addParam("taskId", taskId); - result.addParam("decision", decision); - result.addParam("task-specific data", specific); - result.addContext("user", principal.getUser()); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Completing work item " + taskId); - LOGGER.trace("Decision: " + decision); - LOGGER.trace("WorkItem form object (task-specific) = " + (specific != null ? specific.debugDump() : "(none)")); - LOGGER.trace("User: " + principal.getUser()); - } - - FormService formService = activitiEngine.getFormService(); - TaskFormData data = activitiEngine.getFormService().getTaskFormData(taskId); - - String assigneeOid = data.getTask().getAssignee(); - if (!miscDataUtil.isAuthorizedToSubmit(taskId, assigneeOid)) { - result.recordFatalError("You are not authorized to complete the selected work item."); - LOGGER.error("Authorization failure: task.assigneeOid = {}, principal = {}", assigneeOid, principal); - return; - } - - Map propertiesToSubmit = new HashMap(); - - propertiesToSubmit.put(CommonProcessVariableNames.FORM_FIELD_DECISION, decision); - - // we also fill-in the corresponding 'button' property (if there's one that corresponds to the decision) - for (FormProperty formProperty : data.getFormProperties()) { - if (formProperty.getId().startsWith(CommonProcessVariableNames.FORM_BUTTON_PREFIX)) { - boolean value = formProperty.getId().equals(CommonProcessVariableNames.FORM_BUTTON_PREFIX + decision); - LOGGER.trace("Setting the value of {} to writable property {}", value, formProperty.getId()); - propertiesToSubmit.put(formProperty.getId(), Boolean.toString(value)); - } - } - - if (specific != null) { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("# of form properties: " + data.getFormProperties().size()); - } - - for (FormProperty formProperty : data.getFormProperties()) { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Processing property " + formProperty.getId() + ":" + formProperty.getName()); - } - - if (formProperty.isWritable()) { - - Object value; - - if (!CommonProcessVariableNames.FORM_FIELD_DECISION.equals(formProperty.getId()) && - !formProperty.getId().startsWith(CommonProcessVariableNames.FORM_BUTTON_PREFIX)) { - - // todo strip [flags] section - QName propertyName = new QName(SchemaConstants.NS_WFCF, formProperty.getId()); - value = specific.getPropertyRealValue(propertyName, Object.class); + result.addParams(new String[] { "taskId", "decision", "comment" }, taskId, decision, comment); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Writable property " + formProperty.getId() + " has a value of " + value); - } - - propertiesToSubmit.put(formProperty.getId(), value == null ? "" : value.toString()); - } - } - } - } - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Submitting " + propertiesToSubmit.size() + " properties"); - } - - formService.submitTaskFormData(taskId, propertiesToSubmit); - - result.recordSuccessIfUnknown(); + try { + final String userDecription = toShortString(securityEnforcer.getPrincipal().getUser()); + result.addContext("user", userDecription); + + LOGGER.trace("Completing work item {} with decision of {} ['{}'] by {}", taskId, decision, comment, userDecription); + + FormService formService = activitiEngine.getFormService(); + TaskFormData data = activitiEngine.getFormService().getTaskFormData(taskId); + + String assigneeOid = data.getTask().getAssignee(); + if (!miscDataUtil.isAuthorizedToSubmit(taskId, assigneeOid)) { + throw new SecurityViolationException("You are not authorized to complete this work item."); + } + + final Map propertiesToSubmit = new HashMap<>(); + propertiesToSubmit.put(CommonProcessVariableNames.FORM_FIELD_DECISION, decision); + if (comment != null) { + propertiesToSubmit.put(CommonProcessVariableNames.FORM_FIELD_COMMENT, comment); + } + + // we also fill-in the corresponding 'button' property (if there's one that corresponds to the decision) + for (FormProperty formProperty : data.getFormProperties()) { + if (formProperty.getId().startsWith(CommonProcessVariableNames.FORM_BUTTON_PREFIX)) { + boolean value = formProperty.getId().equals(CommonProcessVariableNames.FORM_BUTTON_PREFIX + decision); + LOGGER.trace("Setting the value of {} to writable property {}", value, formProperty.getId()); + propertiesToSubmit.put(formProperty.getId(), Boolean.toString(value)); + } + } + LOGGER.trace("Submitting {} properties", propertiesToSubmit.size()); + formService.submitTaskFormData(taskId, propertiesToSubmit); + } catch (SecurityViolationException|RuntimeException e) { + result.recordFatalError("Couldn't complete the work item " + taskId + ": " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); + } } - - public void claimWorkItem(String taskId, OperationResult parentResult) { - MidPointPrincipal principal; - try { - principal = securityEnforcer.getPrincipal(); - } catch (SecurityViolationException e) { - LOGGER.error("Security violation: {}", e.getMessage(), e); - return; - } - + public void claimWorkItem(String taskId, OperationResult parentResult) throws SecurityViolationException, ObjectNotFoundException { OperationResult result = parentResult.createSubresult(OPERATION_CLAIM_WORK_ITEM); result.addParam("taskId", taskId); - result.addContext("user", principal.getUser()); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Claiming work item " + taskId); - LOGGER.trace("User: " + principal.getUser()); - } - - try { - TaskService taskService = activitiEngine.getTaskService(); - Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); - if (task == null) { - result.recordFatalError("Couldn't claim work item " + taskId + ", because it does not exist"); - return; - } - if (task.getAssignee() != null) { - String desc = task.getAssignee().equals(principal.getOid()) ? - "the current" : "another"; - result.recordFatalError("Couldn't claim work item " + taskId + ", because it is already assigned to "+desc+" user"); - return; - } - if (!miscDataUtil.isAuthorizedToClaim(task.getId())) { - result.recordFatalError("Current user is not authorized to claim the selected work item."); - return; - } - taskService.claim(taskId, principal.getOid()); - result.recordSuccess(); - } catch (ActivitiException e) { - result.recordFatalError("Couldn't claim work item " + taskId + ": " + e.getMessage(), e); - } - } - - public void releaseWorkItem(String taskId, OperationResult parentResult) { - MidPointPrincipal principal; - try { - principal = securityEnforcer.getPrincipal(); - } catch (SecurityViolationException e) { - LOGGER.error("Security violation: {}", e.getMessage(), e); - parentResult.recordFatalError("Security violation: " + e.getMessage(), e); - return; - } + try { + MidPointPrincipal principal = securityEnforcer.getPrincipal(); + result.addContext("user", toShortString(principal.getUser())); + + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Claiming work item {} by {}", taskId, toShortString(principal.getUser())); + } + + TaskService taskService = activitiEngine.getTaskService(); + Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); + if (task == null) { + throw new ObjectNotFoundException("The work item does not exist"); + } + if (task.getAssignee() != null) { + String desc = task.getAssignee().equals(principal.getOid()) ? "the current" : "another"; + throw new SystemException("The work item is already assigned to "+desc+" user"); + } + if (!miscDataUtil.isAuthorizedToClaim(task.getId())) { + throw new SecurityViolationException("You are not authorized to claim the selected work item."); + } + taskService.claim(taskId, principal.getOid()); + } catch (ObjectNotFoundException|SecurityViolationException|RuntimeException e) { + result.recordFatalError("Couldn't claim the work item " + taskId + ": " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); + } + } + public void releaseWorkItem(String taskId, OperationResult parentResult) throws ObjectNotFoundException, SecurityViolationException { OperationResult result = parentResult.createSubresult(OPERATION_RELEASE_WORK_ITEM); result.addParam("taskId", taskId); - result.addContext("user", principal.getUser()); + try { + MidPointPrincipal principal = securityEnforcer.getPrincipal(); + result.addContext("user", toShortString(principal.getUser())); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Releasing work item " + taskId); - LOGGER.trace("User: " + principal.getUser()); - } + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Releasing work item {} by {}", taskId, toShortString(principal.getUser())); + } - try { TaskService taskService = activitiEngine.getTaskService(); Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if (task == null) { - result.recordFatalError("Couldn't release work item " + taskId + ", because it does not exist"); - return; + throw new ObjectNotFoundException("The work item does not exist"); } if (task.getAssignee() == null) { - result.recordFatalError("Couldn't release work item " + taskId + ", because it is not assigned to a user"); - return; + throw new SystemException("The work item is not assigned to a user"); } if (!task.getAssignee().equals(principal.getOid())) { - result.recordFatalError("Couldn't release work item " + taskId + ", because it is not assigned to the current user"); - return; + throw new SystemException("The work item is not assigned to the current user"); } boolean candidateFound = false; for (IdentityLink link : taskService.getIdentityLinksForTask(taskId)) { @@ -252,13 +172,14 @@ public void releaseWorkItem(String taskId, OperationResult parentResult) { } } if (!candidateFound) { - result.recordFatalError("Couldn't release work item " + taskId + ", because it has no candidates to be offered to"); - return; + throw new SystemException("It has no candidates to be offered to"); } taskService.unclaim(taskId); - result.recordSuccess(); - } catch (ActivitiException e) { + } catch (ObjectNotFoundException|SecurityViolationException|RuntimeException e) { result.recordFatalError("Couldn't release work item " + taskId + ": " + e.getMessage(), e); - } + throw e; + } finally { + result.computeStatusIfUnknown(); + } } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/WorkItemProvider.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/WorkItemProvider.java index f65b193f6f3..7b41480682f 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/WorkItemProvider.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/dao/WorkItemProvider.java @@ -17,55 +17,50 @@ package com.evolveum.midpoint.wf.impl.activiti.dao; import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; +import com.evolveum.midpoint.prism.PrismPropertyValue; +import com.evolveum.midpoint.prism.PrismReferenceValue; +import com.evolveum.midpoint.prism.PrismValue; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.prism.query.ObjectPaging; +import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.constants.SchemaConstants; +import com.evolveum.midpoint.schema.GetOperationOptions; +import com.evolveum.midpoint.schema.SearchResultList; +import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.MiscSchemaUtil; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.api.WorkflowException; -import com.evolveum.midpoint.wf.api.WorkflowManager; -import com.evolveum.midpoint.wf.impl.WfConfiguration; import com.evolveum.midpoint.wf.impl.WorkflowManagerImpl; import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine; -import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngineDataHelper; import com.evolveum.midpoint.wf.impl.messages.TaskEvent; +import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; +import com.evolveum.midpoint.wf.impl.processes.ProcessMidPointInterface; import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; +import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRef; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AbstractRoleType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.TrackingDataType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; - -import org.activiti.engine.ActivitiException; import org.activiti.engine.TaskService; -import org.activiti.engine.runtime.ProcessInstanceQuery; import org.activiti.engine.task.IdentityLink; import org.activiti.engine.task.IdentityLinkType; import org.activiti.engine.task.Task; import org.activiti.engine.task.TaskQuery; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; -import javax.xml.bind.JAXBException; +import java.util.*; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import static com.evolveum.midpoint.schema.constants.ObjectTypes.TASK; +import static com.evolveum.midpoint.schema.constants.ObjectTypes.USER; +import static com.evolveum.midpoint.schema.util.ObjectQueryUtil.FilterComponents; +import static com.evolveum.midpoint.schema.util.ObjectQueryUtil.factorOutQuery; +import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.createObjectRef; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType.*; +import static org.apache.commons.collections.CollectionUtils.isNotEmpty; +import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; /** * Used to retrieve (and provide) data about work items. @@ -81,145 +76,126 @@ public class WorkItemProvider { @Autowired private ActivitiEngine activitiEngine; - @Autowired - private ActivitiEngineDataHelper activitiEngineDataHelper; - - @Autowired - private WfConfiguration wfConfiguration; - @Autowired private MiscDataUtil miscDataUtil; @Autowired private PrismContext prismContext; - @Autowired - @Qualifier("cacheRepositoryService") - private RepositoryService repositoryService; + @Autowired + private ProcessInterfaceFinder processInterfaceFinder; private static final String DOT_CLASS = WorkflowManagerImpl.class.getName() + "."; - private static final String DOT_INTERFACE = WorkflowManager.class.getName() + "."; - private static final String OPERATION_COUNT_WORK_ITEMS_RELATED_TO_USER = DOT_INTERFACE + "countWorkItemsRelatedToUser"; - private static final String OPERATION_LIST_WORK_ITEMS_RELATED_TO_USER = DOT_INTERFACE + "listWorkItemsRelatedToUser"; private static final String OPERATION_ACTIVITI_TASK_TO_WORK_ITEM = DOT_CLASS + "activitiTaskToWorkItem"; - private static final String OPERATION_ACTIVITI_DELEGATE_TASK_TO_WORK_ITEM = DOT_CLASS + "activitiDelegateTaskToWorkItem"; - private static final String OPERATION_GET_WORK_ITEM_DETAILS_BY_TASK_ID = DOT_CLASS + "getWorkItemDetailsById"; - - /* - * ========================= PART 1 - main operations ========================= - */ - /** - * Counts Work Items related to a user. - * - * @param userOid OID of the user - * @param assigned whether to count assigned (true) or assignable (false) work items - * @param parentResult - * @return number of relevant work items - * @throws WorkflowException - */ - public int countWorkItemsRelatedToUser(String userOid, boolean assigned, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - OperationResult result = parentResult.createSubresult(OPERATION_COUNT_WORK_ITEMS_RELATED_TO_USER); - result.addParam("userOid", userOid); - result.addParam("assigned", assigned); - try { - int count = (int) createQueryForTasksRelatedToUser(userOid, assigned, result).count(); - result.recordSuccess(); - return count; - } catch (ActivitiException e) { - result.recordFatalError("Couldn't count work items assigned/assignable to " + userOid, e); - throw new SystemException("Couldn't count work items assigned/assignable to " + userOid + " due to Activiti exception", e); + public Integer countWorkItems(ObjectQuery query, Collection> options, OperationResult result) throws SchemaException { + TaskQuery taskQuery = createTaskQuery(query, options, result); + return (int) taskQuery.count(); + } + + public SearchResultList searchWorkItems(ObjectQuery query, Collection> options, OperationResult result) + throws SchemaException { + TaskQuery taskQuery = createTaskQuery(query, options, result); + Integer offset = query != null ? query.getOffset() : null; + Integer maxSize = query != null ? query.getMaxSize() : null; + List tasks; + if (offset == null && maxSize == null) { + tasks = taskQuery.list(); + } else { + tasks = taskQuery.listPage(defaultIfNull(offset, 0), defaultIfNull(maxSize, Integer.MAX_VALUE)); + } + // there's no need to fill-in assignee details ; but candidates are necessary to fill-in; TODO implement based on options (resolve) + return tasksToWorkItemsNew(tasks, null, false, false, true, result); + } + + // primitive 'query interpreter' + private TaskQuery createTaskQuery(ObjectQuery query, Collection> options, OperationResult result) throws SchemaException { + FilterComponents components = factorOutQuery(query, F_ASSIGNEE_REF, F_CANDIDATE_ROLES_REF, F_WORK_ITEM_ID); + if (components.hasRemainder()) { + throw new SchemaException("Unsupported clause(s) in search filter: " + components.getRemainderClauses()); } - } - /** - * Lists work items related to a user. - * - * @param userOid OID of the user - * @param assigned whether to count assigned (true) or assignable (false) work items - * @param first - * @param count - * @param parentResult - * @return list of work items - * @throws WorkflowException - */ - public List listWorkItemsRelatedToUser(String userOid, boolean assigned, int first, int count, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - OperationResult result = parentResult.createSubresult(OPERATION_LIST_WORK_ITEMS_RELATED_TO_USER); - result.addParam("userOid", userOid); - result.addParam("assigned", assigned); - result.addParam("first", first); - result.addParam("count", count); - List tasks; - try { - tasks = createQueryForTasksRelatedToUser(userOid, assigned, result).listPage(first, count); - } catch (ActivitiException e) { - result.recordFatalError("Couldn't list work items assigned/assignable to " + userOid, e); - throw new SystemException("Couldn't list work items assigned/assignable to " + userOid + " due to Activiti exception", e); - } + final ItemPath WORK_ITEM_ID_PATH = new ItemPath(F_WORK_ITEM_ID); + final ItemPath ASSIGNEE_PATH = new ItemPath(F_ASSIGNEE_REF); + final ItemPath CANDIDATE_ROLES_PATH = new ItemPath(F_CANDIDATE_ROLES_REF); + final ItemPath CREATED_PATH = new ItemPath(WorkItemType.F_WORK_ITEM_CREATED_TIMESTAMP); - List retval = tasksToWorkItems(tasks, false, false, true, result); // there's no need to fill-in assignee details nor data forms; but candidates are necessary to fill-in - result.computeStatusIfUnknown(); - return retval; - } + final Map.Entry> workItemIdFilter = components.getKnownComponent(WORK_ITEM_ID_PATH); + final Map.Entry> assigneeFilter = components.getKnownComponent(ASSIGNEE_PATH); + final Map.Entry> candidateRolesFilter = components.getKnownComponent(CANDIDATE_ROLES_PATH); + + TaskQuery taskQuery = activitiEngine.getTaskService().createTaskQuery(); + + if (workItemIdFilter != null) { + taskQuery = taskQuery.taskId(((PrismPropertyValue) workItemIdFilter.getValue().iterator().next()).getValue()); + } - private TaskQuery createQueryForTasksRelatedToUser(String oid, boolean assigned, OperationResult result) throws SchemaException, ObjectNotFoundException { - if (assigned) { - return activitiEngine.getTaskService().createTaskQuery().taskAssignee(oid).orderByTaskCreateTime().desc(); - } else { - return activitiEngine.getTaskService().createTaskQuery().taskUnassigned().taskCandidateGroupIn(miscDataUtil.getGroupsForUser(oid, result)).orderByTaskCreateTime().desc(); + if (assigneeFilter != null) { + if (isNotEmpty(assigneeFilter.getValue())) { + if (assigneeFilter.getValue().size() > 1) { + throw new SchemaException("Filter with more than one assignee is not supported: " + assigneeFilter.getValue()); + } + taskQuery = taskQuery.taskAssignee(((PrismReferenceValue) assigneeFilter.getValue().iterator().next()).getOid()); + } else { + taskQuery = taskQuery.taskUnassigned(); + } } - } - public WorkItemType getWorkItemDetailsById(String taskId, OperationResult parentResult) throws ObjectNotFoundException { - OperationResult result = parentResult.createSubresult(OPERATION_GET_WORK_ITEM_DETAILS_BY_TASK_ID); - result.addParam("taskId", taskId); - Task task; - try { - task = activitiEngineDataHelper.getTaskById(taskId, result); - } catch (ActivitiException e) { - result.recordFatalError("Couldn't get work item with id " + taskId, e); - throw new SystemException("Couldn't get work item with id " + taskId, e); + if (candidateRolesFilter != null) { + taskQuery = taskQuery.taskCandidateGroupIn(ObjectTypeUtil.referenceValueListToOidList((Collection) candidateRolesFilter.getValue())); } - WorkItemType retval; - try { - retval = taskToWorkItem(task, true, true, true, result); - } catch (WorkflowException e) { - throw new SystemException(e); + + if (query != null && query.getPaging() != null) { + ObjectPaging paging = query.getPaging(); + if (paging.getOrderingInstructions().size() > 1) { + throw new UnsupportedOperationException("Ordering by more than one property is not supported: " + paging.getOrderingInstructions()); + } else if (paging.getOrderingInstructions().size() == 1) { + ItemPath orderBy = paging.getOrderBy(); + if (CREATED_PATH.equivalent(orderBy)) { + taskQuery = taskQuery.orderByTaskCreateTime(); + } else { + throw new UnsupportedOperationException("Ordering by " + orderBy + " is not currently supported"); + } + + switch (paging.getDirection()) { + case DESCENDING: taskQuery = taskQuery.desc(); break; + case ASCENDING: + default: taskQuery = taskQuery.asc(); break; + } + } } - result.computeStatusIfUnknown(); - return retval; + + return taskQuery + .includeTaskLocalVariables() + .includeProcessVariables(); } - /* - * ========================= PART 2 - activiti to midpoint converters ========================= - * - * getTaskDetails parameter influences whether we want to get only basic or more detailed information. - * The details contain the following information: - * - requester details, - * - object details, - * - all forms needed to display the work item, - * so, obviously, it is more expensive to obtain. - * - * In similar way, getAssigneeDetails influences whether details about assignee are filled-in. - * And getCandidateDetails influences whether details about candidate users and groups are filled-in. - * This should be skipped if there's no need to display these (e.g. in the list of work items assigned to the current user). - */ + // special interface for ProcessInstanceProvider - TODO align with other interfaces + public SearchResultList getWorkItemsForProcessInstanceId(String processInstanceId, OperationResult result) { + TaskService ts = activitiEngine.getTaskService(); + List tasks = ts.createTaskQuery() + .processInstanceId(processInstanceId) + .includeTaskLocalVariables() + .includeProcessVariables() + .list(); + return tasksToWorkItemsNew(tasks, null, false, true, true, result); + } - List tasksToWorkItems(List tasks, boolean getTaskDetails, boolean getAssigneeDetails, boolean getCandidateDetails, OperationResult result) { - List retval = new ArrayList(); + private SearchResultList tasksToWorkItemsNew(List tasks, Map processVariables, + boolean resolveTask, boolean resolveAssignee, boolean resolveCandidates, OperationResult result) { + SearchResultList retval = new SearchResultList<>(new ArrayList()); for (Task task : tasks) { try { - retval.add(taskToWorkItem(task, getTaskDetails, getAssigneeDetails, getCandidateDetails, result)); - } catch (WorkflowException e) { - LoggingUtils.logException(LOGGER, "Couldn't get information on activiti task {}", e, task.getId()); + retval.add(taskToWorkItemNew(task, processVariables, resolveTask, resolveAssignee, resolveCandidates, result)); + } catch (RuntimeException e) { + // operation result already contains corresponding error record + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get information on activiti task {}", e, task.getId()); } } return retval; } - // should not throw ActivitiException - /** * Helper class to carry relevant data from both Task and DelegateTask (to avoid code duplication) */ @@ -267,17 +243,6 @@ private class TaskExtract { } } -// TaskExtract(DelegateTask task) { -// id = task.getId(); -// assignee = task.getAssignee(); -// name = task.getName(); -// processInstanceId = task.getProcessInstanceId(); -// createTime = task.getCreateTime(); -// owner = task.getOwner(); -// executionId = task.getExecutionId(); -// variables = task.getVariables(); -// } - TaskExtract(TaskEvent task) { id = task.getTaskId(); assignee = task.getAssigneeOid(); @@ -291,6 +256,17 @@ private class TaskExtract { candidateGroups = task.getCandidateGroups(); } + public TaskExtract(Task task, Map processVariables) { + this(task); + if (processVariables != null) { + for (Map.Entry variable: processVariables.entrySet()) { + if (!variables.containsKey(variable.getKey())) { + variables.put(variable.getKey(), variable.getValue()); + } + } + } + } + String getId() { return id; } @@ -341,181 +317,73 @@ public String toString() { } } - private WorkItemType taskToWorkItem(Task task, boolean getTaskDetails, boolean getAssigneeDetails, boolean getCandidateDetails, OperationResult parentResult) throws WorkflowException { - OperationResult result = parentResult.createSubresult(OPERATION_ACTIVITI_TASK_TO_WORK_ITEM); - result.addParam("task id", task.getId()); - result.addParam("getTaskDetails", getTaskDetails); - result.addParam("getAssigneeDetails", getAssigneeDetails); - - TaskExtract taskExtract = new TaskExtract(task); - WorkItemType wi = taskExtractToWorkItem(taskExtract, getAssigneeDetails, getCandidateDetails, result); - - // this could be moved to taskExtractToWorkType after changing ChangeProcessor interface to accept TaskExtract instead of Task - if (getTaskDetails) { - try { - Map variables = activitiEngineDataHelper.getProcessVariables(task.getId(), result); - ChangeProcessor cp = getChangeProcessor(taskExtract, variables); - - PrismObject requester = miscDataUtil.getRequester(variables, result); - wi.setRequester(requester.asObjectable()); - wi.setRequesterRef(MiscSchemaUtil.createObjectReference(requester.getOid(), SchemaConstants.C_USER_TYPE)); - - wi.setContents(asObjectable(cp.externalizeWorkItemContents(task, variables, result))); - - wi.setTrackingData(asObjectable(getTrackingData(taskExtract, variables, result))); - } catch (SchemaException e) { - throw new SystemException("Got unexpected schema exception when preparing information on Work Item", e); - } catch (ObjectNotFoundException e) { - throw new SystemException("Got unexpected object-not-found exception when preparing information on Work Item; perhaps the requester or a workflow task was deleted in the meantime.", e); - } catch (JAXBException e) { - throw new SystemException("Got unexpected JAXB exception when preparing information on Work Item", e); - } catch (WorkflowException e) { - result.recordFatalError("Couldn't set work item details for activiti task " + task.getId(), e); - throw e; - } - } - result.recordSuccessIfUnknown(); - return wi; + private WorkItemType taskToWorkItemNew(Task task, Map processVariables, boolean resolveTask, boolean resolveAssignee, + boolean resolveCandidates, OperationResult result) { + TaskExtract taskExtract = new TaskExtract(task, processVariables); + return taskExtractToWorkItemNew(taskExtract, resolveTask, resolveAssignee, resolveCandidates, result); } - // this method should reside outside activiti-related packages - // we'll deal with it when we implement support for multiple wf providers - public WorkItemType taskEventToWorkItem(TaskEvent taskEvent, boolean getAssigneeDetails, boolean getCandidateDetails, OperationResult parentResult) throws WorkflowException { - OperationResult result = parentResult.createSubresult(OPERATION_ACTIVITI_DELEGATE_TASK_TO_WORK_ITEM); - result.addParam("task id", taskEvent.getTaskId()); - result.addParam("getAssigneeDetails", getAssigneeDetails); - - WorkItemType wi = taskExtractToWorkItem(new TaskExtract(taskEvent), getAssigneeDetails, getCandidateDetails, result); - result.recordSuccessIfUnknown(); - return wi; + public WorkItemType taskEventToWorkItemNew(TaskEvent taskEvent, Map processVariables, boolean resolveTask, + boolean resolveAssignee, boolean resolveCandidates, OperationResult result) { + TaskExtract taskExtract = new TaskExtract(taskEvent); + return taskExtractToWorkItemNew(taskExtract, resolveTask, resolveAssignee, resolveCandidates, result); } - private WorkItemType taskExtractToWorkItem(TaskExtract task, boolean getAssigneeDetails, boolean getCandidateDetails, OperationResult result) throws WorkflowException { - WorkItemType wi = prismContext.createObject(WorkItemType.class).asObjectable(); - try { - wi.setWorkItemId(task.getId()); - if (task.getAssignee() != null) { - wi.setAssigneeRef(MiscSchemaUtil.createObjectReference(task.getAssignee(), SchemaConstants.C_USER_TYPE)); - } - for (String candidateUser : task.getCandidateUsers()) { - wi.getCandidateUsersRef().add(MiscSchemaUtil.createObjectReference(candidateUser, SchemaConstants.C_USER_TYPE)); - } - for (String candidateGroup : task.getCandidateGroups()) { - wi.getCandidateRolesRef().add(miscDataUtil.groupIdToObjectReference(candidateGroup)); - } - wi.setName(new PolyStringType(task.getName())); - wi.setProcessInstanceId(task.getProcessInstanceId()); - wi.setChangeProcessor((String) task.getVariables().get(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR)); - MetadataType metadataType = new MetadataType(); - metadataType.setCreateTimestamp(XmlTypeConverter.createXMLGregorianCalendar(task.getCreateTime())); - wi.setMetadata(metadataType); - } catch (ActivitiException e) { // not sure if any of the above methods can throw this exception, but for safety we catch it here - result.recordFatalError("Couldn't get information on activiti task " + task.getId(), e); - throw new WorkflowException("Couldn't get information on activiti task " + task.getId(), e); - } - - if (getAssigneeDetails) { - PrismObject assignee = miscDataUtil.getUserByOid(task.getAssignee(), result); - if (assignee != null) { - wi.setAssignee(assignee.asObjectable()); - } - } - if (getCandidateDetails) { - for (ObjectReferenceType ort : wi.getCandidateUsersRef()) { - PrismObject obj = miscDataUtil.getUserByOid(ort.getOid(), result); - if (obj != null) { - wi.getCandidateUsers().add(obj.asObjectable()); - } - } - for (ObjectReferenceType ort : wi.getCandidateRolesRef()) { - PrismObject obj = miscDataUtil.resolveObjectReferenceType(ort, result); - if (obj != null) { - wi.getCandidateRoles().add(obj.asObjectable()); - } - } - } - return wi; - } - - private T asObjectable(PrismObject prismObject) { - return prismObject != null ? prismObject.asObjectable() : null; - } - - private ChangeProcessor getChangeProcessor(TaskExtract task, Map variables) { - String cpClassName = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR); - if (cpClassName == null) { - throw new IllegalStateException("Change processor is unknown for task: " + task); - } - - return wfConfiguration.findChangeProcessor(cpClassName); - } - - private ChangeProcessor getChangeProcessor(Map variables, String context) { - String cpClassName = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR); - if (cpClassName == null) { - throw new IllegalStateException("No change processor in " + context); - } - return wfConfiguration.findChangeProcessor(cpClassName); - } - - private PrismObject getTrackingData(TaskExtract task, Map variables, OperationResult result) throws ObjectNotFoundException, SchemaException { - ProcessInstanceQuery piq = activitiEngine.getRuntimeService().createProcessInstanceQuery(); - piq.processInstanceId(task.getProcessInstanceId()); - org.activiti.engine.runtime.ProcessInstance processInstance = piq.singleResult(); - - PrismObjectDefinition formDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByType(TrackingDataType.COMPLEX_TYPE); - PrismObject formPrism = formDefinition.instantiate(); - TrackingDataType form = formPrism.asObjectable(); - - form.setTaskId(task.getId()); - form.setProcessInstanceId(task.getProcessInstanceId()); - form.setTaskAssignee(task.getAssignee()); - form.setTaskOwner(task.getOwner()); - //form.setTaskCandidates(getCandidatesAsString(task)); - form.setExecutionId(task.getExecutionId()); - form.setProcessDefinitionId(processInstance.getProcessDefinitionId()); - form.setShadowTaskOid((String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID)); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Resulting prism object instance = " + formPrism.debugDump()); - } - return formPrism; - } - -// private List getCandidates(TaskExtract task) { -// -// List retval = new ArrayList(); -// -// TaskService taskService = activitiEngine.getTaskService(); -// -// List ils = taskService.getIdentityLinksForTask(task.getId()); // dangerous (activiti bug) -// for (IdentityLink il : ils) { -// if ("candidate".equals(il.getType())) { -// if (il.getGroupId() != null) { -// retval.add("G:" + il.getGroupId()); -// } -// if (il.getUserId() != null) { -// retval.add("U:" + il.getUserId()); -// } -// } -// } -// -// return retval; -// } -// -// private String getCandidatesAsString(TaskExtract task) { -// -// StringBuilder retval = new StringBuilder(); -// boolean first = true; -// for (String c : getCandidates(task)) { -// if (first) { -// first = false; -// } else { -// retval.append(", "); -// } -// retval.append(c); -// } -// return retval.toString(); -// } - + public WorkItemType taskExtractToWorkItemNew(TaskExtract task, boolean resolveTask, boolean resolveAssignee, boolean resolveCandidates, OperationResult parentResult) { + OperationResult result = parentResult.createSubresult(OPERATION_ACTIVITI_TASK_TO_WORK_ITEM); + result.addParams(new String [] { "activitiTaskId", "resolveTask", "resolveAssignee", "resolveCandidates" }, + task.getId(), resolveTask, resolveAssignee, resolveCandidates); + try { + + WorkItemType wi = new WorkItemType(prismContext); + final Map variables = task.getVariables(); + + wi.setWorkItemId(task.getId()); + wi.setName(task.getName()); + wi.setWorkItemCreatedTimestamp(XmlTypeConverter.createXMLGregorianCalendar(task.getCreateTime())); + wi.setProcessStartedTimestamp(XmlTypeConverter.createXMLGregorianCalendar((Date) variables.get(CommonProcessVariableNames.VARIABLE_START_TIME))); + String taskOid = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID); + if (taskOid != null) { + wi.setTaskRef(createObjectRef(taskOid, TASK)); + if (resolveTask) { + miscDataUtil.resolveAndStoreObjectReference(wi.getTaskRef(), result); + } + } + if (task.getAssignee() != null) { + wi.setAssigneeRef(createObjectRef(task.getAssignee(), USER)); + if (resolveAssignee) { + miscDataUtil.resolveAndStoreObjectReference(wi.getAssigneeRef(), result); + } + } + for (String candidateUser : task.getCandidateUsers()) { + wi.getCandidateUsersRef().add(createObjectRef(candidateUser, USER)); + if (resolveCandidates) { + for (ObjectReferenceType ref : wi.getCandidateUsersRef()) { + miscDataUtil.resolveAndStoreObjectReference(ref, result); + } + } + } + for (String candidateGroup : task.getCandidateGroups()) { + wi.getCandidateRolesRef().add(miscDataUtil.groupIdToObjectReference(candidateGroup)); + if (resolveCandidates) { + for (ObjectReferenceType ref : wi.getCandidateRolesRef()) { + miscDataUtil.resolveAndStoreObjectReference(ref, result); + } + } + } + wi.setObjectRef(MiscDataUtil.toObjectReferenceType((LightweightObjectRef) variables.get(CommonProcessVariableNames.VARIABLE_OBJECT_REF))); + wi.setTargetRef(MiscDataUtil.toObjectReferenceType((LightweightObjectRef) variables.get(CommonProcessVariableNames.VARIABLE_TARGET_REF))); + + ProcessMidPointInterface pmi = processInterfaceFinder.getProcessInterface(variables); + wi.setDecision(pmi.extractDecision(variables)); + + return wi; + + } catch (RuntimeException e) { + result.recordFatalError("Couldn't convert activiti task " + task.getId() + " to midPoint WorkItem: " + e.getMessage(), e); + throw e; + } finally { + result.computeStatusIfUnknown(); + } + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/users/MidPointUserManager.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/users/MidPointUserManager.java index 4d63be715d1..523fa4c8115 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/users/MidPointUserManager.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/activiti/users/MidPointUserManager.java @@ -35,11 +35,6 @@ public void insertUser(User user) { throw new UnsupportedOperationException("MidPoint user manager doesn't support inserting a new user"); } -// @Override -// public void updateUser(User updatedUser) { -// throw new UnsupportedOperationException("MidPoint user manager doesn't support updating a user"); -// } - @Override public UserEntity findUserById(String userId) { throw new UnsupportedOperationException("MidPoint user manager doesn't support finding a user by id"); @@ -50,65 +45,6 @@ public void deleteUser(String userId) { throw new UnsupportedOperationException("MidPoint user manager doesn't support deleting a user"); } -// @Override -// public List findUserByQueryCriteria(Object query, Page page) { -// -// throw new UnsupportedOperationException("MidPoint user manager doesn't support finding a user by query criteria"); - -// List userList = new ArrayList(); -// -// // Query is a UserQueryImpl instance -// UserQueryImpl userQuery = (UserQueryImpl) query; -// StringBuilder searchQuery = new StringBuilder(); -// if (StringUtils.isNotEmpty(userQuery.getId())) { -// searchQuery.append("(uid=").append(userQuery.getId()).append(")"); -// -// } else if (StringUtils.isNotEmpty(userQuery.getLastName())) { -// searchQuery.append("(sn=").append(userQuery.getLastName()).append(")"); -// -// } else { -// searchQuery.append("(uid=*)"); -// } -// LdapConnection connection = LDAPConnectionUtil.openConnection(connectionParams); -// try { -// Cursor cursor = connection.search(USER_GROUP, searchQuery.toString(), SearchScope.ONELEVEL, "*"); -// while (cursor.next()) { -// User user = new UserEntity(); -// SearchResultEntry response = (SearchResultEntry) cursor.get(); -// Iterator itEntry = response.getEntry().iterator(); -// while (itEntry.hasNext()) { -// EntryAttribute attribute = itEntry.next(); -// String key = attribute.getId(); -// if ("uid".equalsIgnoreCase(key)) { -// user.setId(attribute.getString()); -// -// } else if ("sn".equalsIgnoreCase(key)) { -// user.setLastName(attribute.getString()); -// -// } else if ("cn".equalsIgnoreCase(key)) { -// user.setFirstName(attribute.getString().substring(0, attribute.getString().indexOf(" "))); -// } -// } -// -// userList.add(user); -// } -// -// cursor.close(); -// -// } catch (Exception e) { -// throw new ActivitiException("LDAP connection search failure", e); -// } -// -// LDAPConnectionUtil.closeConnection(connection); -// -// return userList; -// } - -// @Override -// public long findUserCountByQueryCriteria(Object query) { -// return findUserByQueryCriteria(query, null).size(); -// } - @Override public Boolean checkPassword(String userId, String password) { return true; diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/Job.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/Job.java deleted file mode 100644 index faf15cae3a2..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/Job.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.evolveum.midpoint.wf.impl.jobs; - -import com.evolveum.midpoint.model.api.context.ModelContext; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskExecutionStatus; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; -import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import org.apache.commons.lang3.Validate; - -import java.util.ArrayList; -import java.util.List; - -/** - * A class that describes jobs related to workflow module: - * - typically, a workflow process instances - * - but sometimes also jobs without workflow -> e.g. tasks that carry out modifications that don't require approval. - * - * It points to the activiti process instance information as well as to the corresponding midPoint task. - * - * @author mederly - */ -public class Job { - - private JobController jobController; - - private Task task; // must be non-null - private String activitiId; // must be non-null for Activiti-related jobs (and may be filled-in later, when activiti process is started) - private ChangeProcessor changeProcessor; // must be non-null - - //region Constructors and basic getters - Job(JobController jobController, Task task, ChangeProcessor changeProcessor) { - this(jobController, task, null, changeProcessor); - } - - Job(JobController jobController, Task task, String activitiId, ChangeProcessor changeProcessor) { - Validate.notNull(task, "Task"); - Validate.notNull(changeProcessor, "Change processor"); - this.jobController = jobController; - this.task = task; - this.activitiId = activitiId; - this.changeProcessor = changeProcessor; - } - - protected Job(Job original) { - this.jobController = original.jobController; - this.task = original.task; - this.activitiId = original.activitiId; - this.changeProcessor = original.changeProcessor; - } - - public String getActivitiId() { - return activitiId; - } - - public Task getTask() { - return task; - } - - public ChangeProcessor getChangeProcessor() { - return changeProcessor; - } - //endregion - - - @Override - public String toString() { - return "Job{" + - "task=" + task + - ", activitiId='" + activitiId + '\'' + - ", changeProcessor=" + changeProcessor + - '}'; - } - - public void addDependent(Job job) { - jobController.addDependency(this, job); - } - - public void commitChanges(OperationResult result) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { - task.savePendingModifications(result); - } - - public void resumeTask(OperationResult result) throws SchemaException, ObjectNotFoundException { - jobController.resumeTask(this, result); - } - - public void startWaitingForSubtasks(OperationResult result) throws SchemaException, ObjectNotFoundException { - task.startWaitingForTasksImmediate(result); - } - - public void setWfProcessIdImmediate(String pid, OperationResult result) throws SchemaException, ObjectNotFoundException { - activitiId = pid; - jobController.getWfTaskUtil().setWfProcessIdImmediate(task, pid, result); - } - - public void setProcessInstanceFinishedImmediate(boolean value, OperationResult result) throws SchemaException, ObjectNotFoundException { - jobController.getWfTaskUtil().setProcessInstanceFinishedImmediate(task, value, result); - } - - public TaskExecutionStatus getTaskExecutionStatus() { - return task.getExecutionStatus(); - } - - public void removeCurrentTaskHandlerAndUnpause(OperationResult result) throws SchemaException, ObjectNotFoundException { - boolean wasWaiting = getTaskExecutionStatus() == TaskExecutionStatus.WAITING; - task.finishHandler(result); - boolean isWaiting = getTaskExecutionStatus() == TaskExecutionStatus.WAITING; - if (wasWaiting && isWaiting) { // if the task was not closed ... (i.e. if there are other handler(s) on the stack) - jobController.unpauseTask(this, result); - } - } - - public void computeTaskResultIfUnknown(OperationResult result) throws SchemaException, ObjectNotFoundException { - OperationResult taskResult = task.getResult(); - if (result.isUnknown()) { - result.computeStatus(); - } - taskResult.recordStatus(result.getStatus(), result.getMessage(), result.getCause()); - task.setResultImmediate(taskResult, result); - } - - public boolean hasModelContext() { - return getWfTaskUtil().hasModelContext(task); - } - - private WfTaskUtil getWfTaskUtil() { - return jobController.getWfTaskUtil(); - } - - public ModelContext retrieveModelContext(OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { - return getWfTaskUtil().retrieveModelContext(task, result); - } - - public List listChildren(OperationResult result) throws SchemaException { - List jobs = new ArrayList(); - for (Task subtask : task.listSubtasks(result)) { - jobs.add(jobController.recreateChildJob(subtask, this)); - } - return jobs; - } - - public ObjectTreeDeltas retrieveResultingDeltas() throws SchemaException { - return getWfTaskUtil().retrieveResultingDeltas(task); - } - - public void deleteModelOperationContext(OperationResult result) throws SchemaException, ObjectNotFoundException { - getWfTaskUtil().deleteModelOperationContext(task, result); - } - - public void storeModelContext(ModelContext modelContext) throws SchemaException { - getWfTaskUtil().storeModelContext(task, modelContext); - } - - public List listDependents(OperationResult result) throws SchemaException, ObjectNotFoundException { - List jobs = new ArrayList(); - for (Task subtask : task.listDependents(result)) { - jobs.add(jobController.recreateJob(subtask)); - } - return jobs; - } - - public Job getParentJob(OperationResult result) throws SchemaException, ObjectNotFoundException { - Task parentTask = task.getParentTask(result); - return jobController.recreateJob(parentTask); - } -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobContext.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobContext.java deleted file mode 100644 index 8efb6a50e5b..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobContext.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.evolveum.midpoint.wf.impl.jobs; - -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; - -import org.apache.commons.lang.Validate; - -/** - * @author mederly - */ -public class JobContext { - - private String parentTaskOid; - private Task parentTask; - private ChangeProcessor changeProcessor; - - public JobContext(Task parentTask, ChangeProcessor changeProcessor) { - Validate.notNull(parentTask); - Validate.notNull(changeProcessor); - this.parentTask = parentTask; - this.parentTaskOid = parentTask.getOid(); // may be null, however - this.changeProcessor = changeProcessor; - } - - public String getParentTaskOid() { - return parentTaskOid; - } - - public void setParentTaskOid(String parentTaskOid) { - this.parentTaskOid = parentTaskOid; - } - - public Task getParentTask() { - return parentTask; - } - - public void setParentTask(Task parentTask) { - this.parentTask = parentTask; - } - - public ChangeProcessor getChangeProcessor() { - return changeProcessor; - } - - public void setChangeProcessor(ChangeProcessor changeProcessor) { - this.changeProcessor = changeProcessor; - } -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobController.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobController.java deleted file mode 100644 index 45cef672b27..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobController.java +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.jobs; - -import com.evolveum.midpoint.audit.api.AuditEventRecord; -import com.evolveum.midpoint.audit.api.AuditEventStage; -import com.evolveum.midpoint.audit.api.AuditService; -import com.evolveum.midpoint.model.impl.controller.ModelOperationTaskHandler; -import com.evolveum.midpoint.model.impl.lens.LensContext; -import com.evolveum.midpoint.prism.Item; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskCategory; -import com.evolveum.midpoint.task.api.TaskExecutionStatus; -import com.evolveum.midpoint.task.api.TaskManager; -import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; -import com.evolveum.midpoint.util.logging.LoggingUtils; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.WfConfiguration; -import com.evolveum.midpoint.wf.impl.activiti.ActivitiInterface; -import com.evolveum.midpoint.wf.impl.activiti.dao.WorkItemProvider; -import com.evolveum.midpoint.wf.api.ProcessListener; -import com.evolveum.midpoint.wf.api.WorkItemListener; -import com.evolveum.midpoint.wf.api.WorkflowException; -import com.evolveum.midpoint.wf.impl.messages.ActivitiToMidPointMessage; -import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; -import com.evolveum.midpoint.wf.impl.messages.ProcessFinishedEvent; -import com.evolveum.midpoint.wf.impl.messages.ProcessStartedEvent; -import com.evolveum.midpoint.wf.impl.messages.StartProcessCommand; -import com.evolveum.midpoint.wf.impl.messages.TaskCompletedEvent; -import com.evolveum.midpoint.wf.impl.messages.TaskCreatedEvent; -import com.evolveum.midpoint.wf.impl.messages.TaskEvent; -import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; -import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; -import org.apache.commons.lang.Validate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Component; - -import javax.xml.bind.JAXBException; -import java.text.DateFormat; -import java.util.Date; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -/** - * Manages everything related to a activiti process instance, including the task that monitors that process instance. - * - * This class provides a facade over ugly mess of code managing activiti + task pair describing a workflow process instance. - * - * For working with tasks only (e.g. not touching Job structure) it uses wfTaskUtil. - * - * @author mederly - */ -@Component -public class JobController { - - private static final Trace LOGGER = TraceManager.getTrace(JobController.class); - - private static final long TASK_START_DELAY = 5000L; - private static final boolean USE_WFSTATUS = true; - private static final Object DOT_CLASS = JobController.class.getName() + "."; - - private Set processListeners = new HashSet<>(); - private Set workItemListeners = new HashSet<>(); - - //region Spring beans - @Autowired - private WfTaskUtil wfTaskUtil; - - @Autowired - private TaskManager taskManager; - - @Autowired - private ActivitiInterface activitiInterface; - - @Autowired - @Qualifier("cacheRepositoryService") - private RepositoryService repositoryService; - - @Autowired - private AuditService auditService; - - @Autowired - private MiscDataUtil miscDataUtil; - - @Autowired - private WfConfiguration wfConfiguration; - - @Autowired - private WorkItemProvider workItemProvider; - //endregion - - //region Job creation & re-creation - /** - * Creates a job, just as prescribed by the job creation instruction. - * - * @param instruction the job creation instruction - * @param parentJob the job that will be the parent of newly created one; it may be null - */ - - public Job createJob(JobCreationInstruction instruction, Job parentJob, OperationResult result) throws SchemaException, ObjectNotFoundException { - return createJob(instruction, parentJob.getTask(), result); - } - - /** - * As before, but this time we know only the parent task (not a job). - * - * @param instruction the job creation instruction - * @param parentTask the task that will be the parent of the task of newly created job; it may be null - */ - public Job createJob(JobCreationInstruction instruction, Task parentTask, OperationResult result) throws SchemaException, ObjectNotFoundException { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Processing start instruction: " + instruction.debugDump()); - } - - Task task = createTask(instruction, parentTask, result); - Job job = new Job(this, task, instruction.getChangeProcessor()); - if (!instruction.isNoProcess()) { - startWorkflowProcessInstance(job, instruction, result); - } - return job; - } - - /** - * Re-creates a job, based on existing task information. - * - * @param task a task from task-processInstance pair - * @return recreated job - */ - public Job recreateJob(Task task) throws SchemaException, ObjectNotFoundException { - return new Job(this, task, wfTaskUtil.getProcessId(task), wfTaskUtil.getChangeProcessor(task)); - } - - /** - * Re-creates a child job, knowing the task and the parent job. - * - * @param subtask a task from task-processInstance pair - * @param parentJob the parent job - * @return recreated job - */ - public Job recreateChildJob(Task subtask, Job parentJob) { - return new Job(this, subtask, wfTaskUtil.getProcessId(subtask), parentJob.getChangeProcessor()); - } - - /** - * Re-creates a root job, based on existing task information. Does not try to find the wf process instance. - */ - public Job recreateRootJob(Task task) { - return new Job(this, task, wfTaskUtil.getChangeProcessor(task)); - } - //endregion - - //region Working with midPoint tasks - - private Task createTask(JobCreationInstruction instruction, Task parentTask, OperationResult result) throws SchemaException, ObjectNotFoundException { - - ChangeProcessor changeProcessor = instruction.getChangeProcessor(); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("createTask starting; parent task = " + parentTask); - } - - Task task; - if (parentTask != null) { - task = parentTask.createSubtask(); - } else { - task = taskManager.createTaskInstance(); - wfTaskUtil.setTaskOwner(task, instruction.getTaskOwner()); - } - - // initial execution state - if (instruction.isCreateTaskAsSuspended() && instruction.isCreateTaskAsWaiting()) { - throw new IllegalStateException("Both createSuspended and createWaiting attributes are set to TRUE."); - } - if (instruction.isCreateTaskAsSuspended()) { - task.setInitialExecutionStatus(TaskExecutionStatus.SUSPENDED); - } else if (instruction.isCreateTaskAsWaiting()) { - task.setInitialExecutionStatus(TaskExecutionStatus.WAITING); - } - - if (instruction.getTaskObject() != null) { - task.setObjectRef(instruction.getTaskObject().getOid(), instruction.getTaskObject().getDefinition().getTypeName()); - } else if (parentTask != null && parentTask.getObjectRef() != null) { - task.setObjectRef(parentTask.getObjectRef()); - } - wfTaskUtil.setChangeProcessor(task, changeProcessor); - wfTaskUtil.setTaskNameIfEmpty(task, instruction.getTaskName()); - wfTaskUtil.setDefaultTaskOwnerIfEmpty(task, result, this); - task.setCategory(TaskCategory.WORKFLOW); - - // push the handlers, beginning with these that should execute last - wfTaskUtil.pushHandlers(task, instruction.getHandlersAfterModelOperation()); - if (instruction.isExecuteModelOperationHandler()) { - task.pushHandlerUri(ModelOperationTaskHandler.MODEL_OPERATION_TASK_URI, null, null); - } - wfTaskUtil.pushHandlers(task, instruction.getHandlersBeforeModelOperation()); - wfTaskUtil.pushHandlers(task, instruction.getHandlersAfterWfProcess()); - if (instruction.startsWorkflowProcess()) { - wfTaskUtil.pushProcessShadowHandler(instruction.isSimple(), task, TASK_START_DELAY, result); - } - - // put model context + task variables - if (instruction.getTaskModelContext() != null) { - task.setModelOperationContext(((LensContext) instruction.getTaskModelContext()).toLensContextType()); - } - for (Item item : instruction.getTaskVariables().values()) { - task.setExtensionItem(item); - } - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Saving workflow monitoring/execution task: " + task.debugDump()); - } - - taskManager.switchToBackground(task, result); - - return task; - } - - /** - * Beware, in order to make the change permanent, it is necessary to call commitChanges on - * "executesFirst". It is advisable not to modify underlying tasks between 'addDependency' - * and 'commitChanges' because of the savePendingModifications() mechanism that is used here. - * - * @param executesFirst - * @param executesSecond - */ - public void addDependency(Job executesFirst, Job executesSecond) { - Validate.notNull(executesFirst.getTask()); - Validate.notNull(executesSecond.getTask()); - LOGGER.trace("Setting dependency of {} on 'task0' {}", executesSecond, executesFirst); - executesFirst.getTask().addDependent(executesSecond.getTask().getTaskIdentifier()); - } - - public void resumeTask(Job job, OperationResult result) throws SchemaException, ObjectNotFoundException { - taskManager.resumeTask(job.getTask(), result); - } - - public void unpauseTask(Job job, OperationResult result) throws SchemaException, ObjectNotFoundException { - taskManager.unpauseTask(job.getTask(), result); - } - //endregion - - //region Working with Activiti process instances - - private void startWorkflowProcessInstance(Job job, JobCreationInstruction instruction, OperationResult result) { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("startWorkflowProcessInstance starting; instruction = " + instruction); - } - - Task task = job.getTask(); - - // perhaps more useful would be state 'workflow process instance creation HAS BEEN requested'; - // however, if we record process state AFTER the request is sent, it is possible - // that the response would come even before we log the request - recordProcessInstanceState(job, "Workflow process instance creation is being requested.", null, result); - - // prepare and send the start process instance command - StartProcessCommand spc = new StartProcessCommand(); - spc.setTaskOid(task.getOid()); - spc.setProcessName(instruction.getProcessDefinitionKey()); - spc.setSendStartConfirmation(instruction.isSendStartConfirmation()); - spc.setVariablesFrom(instruction.getProcessVariables()); - spc.setProcessOwner(task.getOwner().getOid()); - - try { - activitiInterface.midpoint2activiti(spc, task, result); - auditProcessStart(spc, job, result); - notifyProcessStart(spc, job, result); - } catch (JAXBException|SchemaException|RuntimeException e) { - LoggingUtils.logException(LOGGER, - "Couldn't send a request to start a process instance to workflow management system", e); - recordProcessInstanceState(job, "Workflow process instance creation could not be requested: " + e, null, result); - result.recordPartialError("Couldn't send a request to start a process instance to workflow management system: " + e.getMessage(), e); - throw new SystemException("Workflow process instance creation could not be requested", e); - } - - // final - result.recordSuccessIfUnknown(); - - LOGGER.trace("startWorkflowProcessInstance finished"); - } - - /** - * Processes a message got from workflow engine - either synchronously (while waiting for - * replies after sending - i.e. in a thread that requested the operation), or asynchronously - * (directly from activiti2midpoint, in a separate thread). - * - * @param message an event got from workflow engine - * @param task - * @param asynchronous - * @param result - * @throws Exception - */ - // TODO fix exceptions list - public void processWorkflowMessage(ActivitiToMidPointMessage message, Task task, boolean asynchronous, OperationResult result) throws SchemaException, ObjectNotFoundException, WorkflowException, ObjectAlreadyExistsException, JAXBException { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Received ActivitiToMidPointMessage: " + message); - } - if (message instanceof ProcessEvent) { - Task task1 = getTaskFromEvent((ProcessEvent) message, task, result); - if (asynchronous && task1.getExecutionStatus() != TaskExecutionStatus.WAITING) { - LOGGER.trace("Asynchronous message received in a state different from WAITING (actual state: {}), ignoring it. Task = {}", task1.getExecutionStatus(), task1); - } else { - processProcessEvent((ProcessEvent) message, task1, result); - } - } else if (message instanceof TaskEvent) { - processTaskEvent((TaskEvent) message, result); - } else { - throw new IllegalStateException("Unknown kind of event from Activiti: " + message.getClass()); - } - } - - private Task getTaskFromEvent(ProcessEvent event, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException { - - String taskOid = event.getTaskOid(); - if (taskOid == null) { - throw new IllegalStateException("Got a workflow message without taskOid: " + event.toString()); - } - - if (task != null) { - if (!taskOid.equals(task.getOid())) { - throw new IllegalStateException("TaskOid received from the workflow (" + taskOid + ") is different from current task OID (" + task + "): " + event.toString()); - } - } else { - task = taskManager.getTask(taskOid, result); - } - return task; - } - - private void processProcessEvent(ProcessEvent event, Task task, OperationResult result) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException, JAXBException { - - Job job = recreateJob(task); - - recordProcessInstanceState(job, getStateDescription(event), event, result); - - // let us record process id (if unknown or when getting "process started" event) - if (job.getActivitiId() == null || event instanceof ProcessStartedEvent) { - job.setWfProcessIdImmediate(event.getPid(), result); - } - - // should we finish this task? - if (event instanceof ProcessFinishedEvent || !event.isRunning()) { - processFinishedEvent(event, job, result); - } - } - - private void processFinishedEvent(ProcessEvent event, Job job, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException, JAXBException { - LOGGER.trace("processFinishedEvent starting"); - LOGGER.trace("Calling onProcessEnd on {}", job.getChangeProcessor()); - job.getChangeProcessor().onProcessEnd(event, job, result); - - job.setProcessInstanceFinishedImmediate(true, result); - - auditProcessEnd(event, job, result); - notifyProcessEnd(event, job, result); - - // passive tasks can be 'let go' at this point - if (job.getTaskExecutionStatus() == TaskExecutionStatus.WAITING) { - job.computeTaskResultIfUnknown(result); - job.removeCurrentTaskHandlerAndUnpause(result); // removes WfProcessInstanceShadowTaskHandler - } - LOGGER.trace("processFinishedEvent done"); - } - - private String getStateDescription(ProcessEvent event) { - String pid = event.getPid(); - String stateDescription = event.getState(); - if (stateDescription == null || stateDescription.isEmpty()) { - if (event instanceof ProcessStartedEvent) { - stateDescription = "Workflow process instance has been created (process id " + pid + ")"; - } else if (event instanceof ProcessFinishedEvent) { - stateDescription = "Workflow process instance has ended (process id " + pid + ")"; - } else { - stateDescription = "Workflow process instance has proceeded further (process id " + pid + ")"; - } - } - return stateDescription; - } - - private void recordProcessInstanceState(Job job, String stateDescription, ProcessEvent event, OperationResult parentResult) { - LOGGER.trace("recordProcessInstanceState starting."); - Task task = job.getTask(); - try { - task.setDescription(stateDescription); - if (event != null) { - wfTaskUtil.setWfLastVariables(task, dumpVariables(event)); - } - if (USE_WFSTATUS) { - wfTaskUtil.addWfStatus(task, prepareValueForWfStatusProperty(stateDescription)); - } - wfTaskUtil.setLastDetails(task, stateDescription); - task.savePendingModifications(parentResult); - } catch (Exception ex) { // todo - LoggingUtils.logException(LOGGER, "Couldn't record information from WfMS into task {}", ex, task); - parentResult.recordFatalError("Couldn't record information from WfMS into task " + task, ex); - } - LOGGER.trace("recordProcessInstanceState ending."); - } - - private String prepareValueForWfStatusProperty(String stateDescription) { - // statusTsDt (for wfStatus): [: ] - // (timestamp is to enable easy sorting, [] to easy parsing) - - Date d = new Date(); - DateFormat df = DateFormat.getDateTimeInstance(); - return "[" + d.getTime() + ": " + df.format(d) + "] " + stateDescription; - } - - // variables should be sorted in order for dumpVariables produce nice output - private Map getVariablesSorted(ProcessEvent event) { - TreeMap variables = new TreeMap(); - if (event.getVariables() != null) { - variables.putAll(event.getVariables()); - } - return variables; - } - - // Returns the content of process variables in more-or-less human readable format. - // Sorts variables according to their names, in order to be able to decide whether - // anything has changed since last event coming from the process. - private String dumpVariables(ProcessEvent event) { - - StringBuffer sb = new StringBuffer(); - boolean first = true; - - Map variables = getVariablesSorted(event); - - for (Map.Entry entry: variables.entrySet()) { - if (!first) - sb.append("; "); - sb.append(entry.getKey() + "=" + entry.getValue()); - first = false; - } - - return sb.toString(); - } - - private ChangeProcessor getChangeProcessor(Map variables) { - String cpName = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR); - Validate.notNull(cpName, "Change processor is not defined among process instance variables"); - return wfConfiguration.findChangeProcessor(cpName); - } - - private ChangeProcessor getChangeProcessor(WorkItemType workItemType) { - String cpName = workItemType.getChangeProcessor(); - Validate.notNull(cpName, "Change processor is not defined among process instance variables"); - return wfConfiguration.findChangeProcessor(cpName); - } - - private ChangeProcessor getChangeProcessor(TaskEvent taskEvent) { - return getChangeProcessor(taskEvent.getVariables()); - } - - //endregion - - //region Processing work item (task) events - private void processTaskEvent(TaskEvent taskEvent, OperationResult result) throws WorkflowException { - - // auditing & notifications - - if (taskEvent instanceof TaskCreatedEvent) { - auditWorkItemEvent(taskEvent, AuditEventStage.REQUEST, result); - try { - notifyWorkItemCreated( - taskEvent.getTaskName(), - taskEvent.getAssigneeOid(), - taskEvent.getProcessInstanceName(), - taskEvent.getVariables()); - } catch (JAXBException|SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't send notification about work item create event", e); - } - } else if (taskEvent instanceof TaskCompletedEvent) { - auditWorkItemEvent(taskEvent, AuditEventStage.EXECUTION, result); - try { - notifyWorkItemCompleted( - taskEvent.getTaskName(), - taskEvent.getAssigneeOid(), - taskEvent.getProcessInstanceName(), - taskEvent.getVariables(), - (String) taskEvent.getVariables().get(CommonProcessVariableNames.FORM_FIELD_DECISION)); - } catch (JAXBException|SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't audit work item complete event", e); - } - } - } - //endregion - - //region Auditing and notifications - private void auditProcessStart(StartProcessCommand spc, Job job, OperationResult result) { - auditProcessStartEnd(spc.getVariables(), job, AuditEventStage.REQUEST, result); - } - - private void auditProcessEnd(ProcessEvent event, Job job, OperationResult result) { - auditProcessStartEnd(event.getVariables(), job, AuditEventStage.EXECUTION, result); - } - - private void auditProcessStartEnd(Map variables, Job job, AuditEventStage stage, OperationResult result) { - AuditEventRecord auditEventRecord = getChangeProcessor(variables).prepareProcessInstanceAuditRecord(variables, job, stage, result); - auditService.audit(auditEventRecord, job.getTask()); - } - - private void notifyProcessStart(StartProcessCommand spc, Job job, OperationResult result) throws JAXBException, SchemaException { - PrismObject state = job.getChangeProcessor().externalizeProcessInstanceState(spc.getVariables()); - for (ProcessListener processListener : processListeners) { - processListener.onProcessInstanceStart(state, result); - } - } - - private void notifyProcessEnd(ProcessEvent event, Job job, OperationResult result) throws JAXBException, SchemaException { - PrismObject state = job.getChangeProcessor().externalizeProcessInstanceState(event.getVariables()); - for (ProcessListener processListener : processListeners) { - processListener.onProcessInstanceEnd(state, result); - } - } - - private void notifyWorkItemCreated(String workItemName, String assigneeOid, String processInstanceName, Map processVariables) throws JAXBException, SchemaException { - ChangeProcessor cp = getChangeProcessor(processVariables); - PrismObject state = cp.externalizeProcessInstanceState(processVariables); - for (WorkItemListener workItemListener : workItemListeners) { - workItemListener.onWorkItemCreation(workItemName, assigneeOid, state); - } - } - - private void notifyWorkItemCompleted(String workItemName, String assigneeOid, String processInstanceName, Map processVariables, String decision) throws JAXBException, SchemaException { - ChangeProcessor cp = getChangeProcessor(processVariables); - PrismObject state = cp.externalizeProcessInstanceState(processVariables); - for (WorkItemListener workItemListener : workItemListeners) { - workItemListener.onWorkItemCompletion(workItemName, assigneeOid, state, decision); - } - } - - private void auditWorkItemEvent(TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException { - - Task shadowTask; - try { - String taskOid = (String) taskEvent.getVariables().get(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID); - if (taskOid == null) { - LOGGER.error("Shadow task OID is unknown for work item " + taskEvent.getDebugName() + ", no audit record will be produced."); - return; - } - shadowTask = taskManager.getTask(taskOid, result); - } catch (SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve workflow-related task", e); - return; - } catch (ObjectNotFoundException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve workflow-related task", e); - return; - } - - AuditEventRecord auditEventRecord = getChangeProcessor(taskEvent).prepareWorkItemAuditRecord(taskEvent, stage, result); - auditService.audit(auditEventRecord, shadowTask); - } - - private String getDebugName(WorkItemType workItemType) { - return workItemType.getName() + " (id " + workItemType.getWorkItemId() + ")"; - } - - public void registerProcessListener(ProcessListener processListener) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Registering process listener " + processListener); - } - processListeners.add(processListener); - } - - public void registerWorkItemListener(WorkItemListener workItemListener) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Registering work item listener " + workItemListener); - } - workItemListeners.add(workItemListener); - } - //endregion - - //region Getters and setters - public WfTaskUtil getWfTaskUtil() { - return wfTaskUtil; - } - - //endregion -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobCreationInstruction.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobCreationInstruction.java deleted file mode 100644 index dda1461b26c..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/JobCreationInstruction.java +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.jobs; - -import com.evolveum.midpoint.model.api.context.ModelContext; -import com.evolveum.midpoint.model.impl.lens.LensContext; -import com.evolveum.midpoint.prism.Item; -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismProperty; -import com.evolveum.midpoint.prism.PrismPropertyDefinition; -import com.evolveum.midpoint.task.api.TaskBinding; -import com.evolveum.midpoint.task.api.TaskRecurrence; -import com.evolveum.midpoint.util.DebugDumpable; -import com.evolveum.midpoint.util.DebugUtil; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.wf.impl.processes.ProcessMidPointInterface; -import com.evolveum.midpoint.wf.impl.processes.common.ActivitiUtil; -import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; -import com.evolveum.midpoint.xml.ns._public.common.common_3.LensContextType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ScheduleType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UriStackEntry; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; -import org.apache.commons.lang.Validate; - -import javax.xml.namespace.QName; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * A generic instruction to start a workflow process and/or a task (using umbrella term "a job"). - * May be subclassed in order to add further information. - * - * @author mederly - */ -public class JobCreationInstruction implements DebugDumpable { - - private ChangeProcessor changeProcessor; - - private String processDefinitionKey; // name of wf process to be started (e.g. ItemApproval) - - private Map processVariables = new HashMap<>(); // values of process variables - private Map taskVariables = new HashMap<>(); // items to be put into task extension - private ModelContext taskModelContext; // model context to be put into the task - private PrismObject taskObject; // object to be attached to the task; this object must have its definition available - private PrismObject taskOwner; // if null, owner from parent task will be taken (if there's no parent task, exception will be thrown) - private PolyStringType taskName; // name of task to be created/updated (applies only if the task has no name already) - e.g. "Approve adding role R to U" - - private boolean executeModelOperationHandler; // should the job contain model operation to be executed? - private boolean noProcess; // should the job provide no wf process (only direct execution of model operation)? - - private boolean simple; // is workflow task simple? (i.e. such that requires periodic watching of its state) - private boolean sendStartConfirmation = true; // should we send explicit "process started" event when the process was started by midPoint? - // for listener-enabled processes this can be misleading, because "process started" event could come - // after "process finished" one (for immediately-finishing processes) - // - // unfortunately, it seems we have to live with this (unless we define a "process started" listener) - - private boolean createTaskAsSuspended; // should the task be created in SUSPENDED state? - private boolean createTaskAsWaiting; // should the task be created in WAITING state? - - // what should be executed at a given occasion (in the order of being in this list) - private List handlersAfterModelOperation = new ArrayList<>(); - private List handlersBeforeModelOperation = new ArrayList<>(); - private List handlersAfterWfProcess = new ArrayList<>(); - - //region Constructors - protected JobCreationInstruction(ChangeProcessor changeProcessor) { - Validate.notNull(changeProcessor); - this.changeProcessor = changeProcessor; - } - - protected JobCreationInstruction(Job parentJob) { - this(parentJob.getChangeProcessor()); - } - - public static JobCreationInstruction createModelOperationRootJob(ChangeProcessor changeProcessor, ModelContext modelContext) throws SchemaException { - JobCreationInstruction instruction = new JobCreationInstruction(changeProcessor); - instruction.setNoProcess(true); - instruction.addTaskModelContext(modelContext); - instruction.setExecuteModelOperationHandler(true); - return instruction; - } - - public static JobCreationInstruction createNoModelOperationRootJob(ChangeProcessor changeProcessor) throws SchemaException { - JobCreationInstruction instruction = new JobCreationInstruction(changeProcessor); - instruction.setNoProcess(true); - instruction.setExecuteModelOperationHandler(false); - return instruction; - } - - public static JobCreationInstruction createWfProcessChildJob(ChangeProcessor changeProcessor) { - JobCreationInstruction jci = new JobCreationInstruction(changeProcessor); - prepareWfProcessChildJobInternal(jci); - return jci; - } - - public static JobCreationInstruction createWfProcessChildJob(Job parentJob) { - JobCreationInstruction jci = new JobCreationInstruction(parentJob); - prepareWfProcessChildJobInternal(jci); - return jci; - } - - protected static void prepareWfProcessChildJobInternal(JobCreationInstruction instruction) { - instruction.setNoProcess(false); - instruction.initializeCommonProcessVariables(); - } - - public static JobCreationInstruction createModelOperationChildJob(Job parentJob, ModelContext modelContext) throws SchemaException { - JobCreationInstruction instruction = new JobCreationInstruction(parentJob); - instruction.setNoProcess(true); - instruction.addTaskModelContext(modelContext); - instruction.setExecuteModelOperationHandler(true); - return instruction; - } - //endregion - - // region Simple getters and setters - public boolean isSimple() { - return simple; - } - - public void setSimple(boolean simple) { - this.simple = simple; - } - - public boolean isSendStartConfirmation() { - return sendStartConfirmation; - } - - public void setSendStartConfirmation(boolean sendStartConfirmation) { - this.sendStartConfirmation = sendStartConfirmation; - } - - public void setProcessDefinitionKey(String name) { - processDefinitionKey = name; - } - - public String getProcessDefinitionKey() { - return processDefinitionKey; - } - - public Map getProcessVariables() { - return Collections.unmodifiableMap(processVariables); - } - - public void addProcessVariable(String name, Serializable value) { - processVariables.put(name, value); - } - - private void removeProcessVariable(String name) { - processVariables.remove(name); - } - - public PolyStringType getTaskName() { - return taskName; - } - - public void setTaskName(PolyStringType taskName) { - this.taskName = taskName; - } - - public void setTaskName(String taskName) { - this.taskName = new PolyStringType(taskName); - } - - public boolean isNoProcess() { - return noProcess; - } - - public boolean startsWorkflowProcess() { - return !noProcess; - } - - public void setNoProcess(boolean noProcess) { - this.noProcess = noProcess; - } - - public void setCreateTaskAsSuspended(boolean createTaskAsSuspended) { - this.createTaskAsSuspended = createTaskAsSuspended; - } - - public boolean isCreateTaskAsSuspended() { - return createTaskAsSuspended; - } - - public List getHandlersAfterModelOperation() { - return handlersAfterModelOperation; - } - - public List getHandlersBeforeModelOperation() { - return handlersBeforeModelOperation; - } - - public List getHandlersAfterWfProcess() { - return handlersAfterWfProcess; - } - - public Map getTaskVariables() { - return taskVariables; - } - - public void setExecuteModelOperationHandler(boolean executeModelOperationHandler) { - this.executeModelOperationHandler = executeModelOperationHandler; - } - - public boolean isExecuteModelOperationHandler() { - return executeModelOperationHandler; - } - - public void setTaskObject(PrismObject taskObject) { - this.taskObject = taskObject; - } - - public PrismObject getTaskObject() { - return taskObject; - } - - public void setCreateTaskAsWaiting(boolean createTaskAsWaiting) { - this.createTaskAsWaiting = createTaskAsWaiting; - } - - public boolean isCreateTaskAsWaiting() { - return createTaskAsWaiting; - } - - public ChangeProcessor getChangeProcessor() { - return changeProcessor; - } - - public PrismObject getTaskOwner() { - return taskOwner; - } - - public void setTaskOwner(PrismObject taskOwner) { - this.taskOwner = taskOwner; - } - - public ModelContext getTaskModelContext() { - return taskModelContext; - } - - public void setTaskModelContext(ModelContext taskModelContext) { - this.taskModelContext = taskModelContext; - } - //endregion - - //region Setters for handlers - public void setHandlersBeforeModelOperation(String... handlerUri) { - setHandlers(handlersBeforeModelOperation, createUriStackEntries(handlerUri)); - } - - public void setHandlersAfterModelOperation(String... handlerUri) { - setHandlers(handlersAfterModelOperation, createUriStackEntries(handlerUri)); - } - - public void setHandlersAfterWfProcess(String... handlerUri) { - setHandlers(handlersAfterWfProcess, createUriStackEntries(handlerUri)); - } - - public void addHandlersAfterWfProcessAtEnd(String... handlerUriArray) { - addHandlersAtEnd(handlersAfterWfProcess, createUriStackEntries(handlerUriArray)); - } - - private List createUriStackEntries(String[] handlerUriArray) { - List retval = new ArrayList(); - for (String handlerUri : handlerUriArray) { - retval.add(createUriStackEntry(handlerUri)); - } - return retval; - } - - private void addAtBeginningOfExecutionList(List list, String handlerUri, TaskRecurrence recurrence, ScheduleType scheduleType, TaskBinding taskBinding) { - list.add(0, createUriStackEntry(handlerUri, recurrence, scheduleType, taskBinding)); - } - - private void addAtEndOfExecutionList(List list, String handlerUri, TaskRecurrence recurrence, ScheduleType scheduleType, TaskBinding taskBinding) { - list.add(createUriStackEntry(handlerUri, recurrence, scheduleType, taskBinding)); - } - - private UriStackEntry createUriStackEntry(String handlerUri, TaskRecurrence recurrence, ScheduleType scheduleType, TaskBinding taskBinding) { - UriStackEntry uriStackEntry = new UriStackEntry(); - uriStackEntry.setHandlerUri(handlerUri); - uriStackEntry.setRecurrence(recurrence != null ? recurrence.toTaskType() : null); - uriStackEntry.setSchedule(scheduleType); - uriStackEntry.setBinding(taskBinding != null ? taskBinding.toTaskType() : null); - return uriStackEntry; - } - - private void setHandlers(List list, List uriStackEntry) { - list.clear(); - list.addAll(uriStackEntry); - } - - private void addHandlersAtEnd(List list, List uriStackEntry) { - list.addAll(uriStackEntry); - } - - private UriStackEntry createUriStackEntry(String handlerUri) { - return createUriStackEntry(handlerUri, TaskRecurrence.SINGLE, new ScheduleType(), null); - } - //endregion - - //region Setters for task variables - public void addTaskVariable(PrismPropertyDefinition definition, T realValue) { - PrismProperty property = definition.instantiate(); - property.setRealValue(realValue); - taskVariables.put(definition.getName(), property); - } - - public void addTaskVariableValues(PrismPropertyDefinition definition, Collection realValues) { - PrismProperty property = definition.instantiate(); - for (T realValue : realValues) { - property.addRealValue(realValue); - } - taskVariables.put(definition.getName(), property); - } - - public void addTaskModelContext(ModelContext modelContext) throws SchemaException { - Validate.notNull(modelContext, "model context cannot be null"); - setTaskModelContext(modelContext); - } - //endregion - - //region Setters for process variables - public void initializeCommonProcessVariables() { - addProcessVariable(CommonProcessVariableNames.VARIABLE_UTIL, new ActivitiUtil()); - addProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR, changeProcessor.getClass().getName()); - addProcessVariable(CommonProcessVariableNames.VARIABLE_START_TIME, new Date()); - } - - public void setRequesterOidInProcess(PrismObject requester) { - addProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_REQUESTER_OID, requester.getOid()); - } - - public void setObjectOidInProcess(String objectOid) { - if (objectOid != null) { - addProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID, objectOid); - } else { - removeProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID); - } - } - - public void setProcessInstanceName(String name) { - addProcessVariable(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME, name); - } - - public void setProcessInterfaceBean(ProcessMidPointInterface processInterfaceBean) { - addProcessVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_PROCESS_INTERFACE_BEAN_NAME, processInterfaceBean.getBeanName()); - } - //endregion - - //region Diagnostics - public String toString() { - return "JobCreationInstruction: processDefinitionKey = " + processDefinitionKey + ", simple: " + simple + ", variables: " + processVariables; - } - - @Override - public String debugDump() { - return debugDump(0); - } - - @Override - public String debugDump(int indent) { - StringBuilder sb = new StringBuilder(); - - DebugUtil.indentDebugDump(sb, indent); - sb.append("JobCreationInstruction: process: " + processDefinitionKey + " (" + - (simple ? "simple" : "smart") + ", " + - (noProcess ? "no-process" : "with-process") + - "), task = " + taskName + "\n"); - - if (!noProcess) { - DebugUtil.indentDebugDump(sb, indent); - sb.append("Process variables:\n"); - - for (Map.Entry entry : processVariables.entrySet()) { - DebugUtil.indentDebugDump(sb, indent); - sb.append(" - " + entry.getKey() + " = "); - Object value = entry.getValue(); - if (value instanceof DebugDumpable) { - sb.append("\n" + ((DebugDumpable) value).debugDump(indent+1)); - } else { - sb.append(value != null ? value.toString() : "null"); - } - sb.append("\n"); - } - } - return sb.toString(); - - } - //endregion - -} \ No newline at end of file diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/WfTaskUtil.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/WfTaskUtil.java deleted file mode 100644 index dee2063a4aa..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/WfTaskUtil.java +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.jobs; - -import com.evolveum.midpoint.model.api.context.ModelContext; -import com.evolveum.midpoint.model.impl.lens.LensContext; -import com.evolveum.midpoint.prism.Objectable; -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismContainerDefinition; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismProperty; -import com.evolveum.midpoint.prism.PrismPropertyDefinition; -import com.evolveum.midpoint.prism.PrismPropertyValue; -import com.evolveum.midpoint.prism.PrismReference; -import com.evolveum.midpoint.prism.PrismReferenceDefinition; -import com.evolveum.midpoint.prism.PrismReferenceValue; -import com.evolveum.midpoint.prism.delta.ItemDelta; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.provisioning.api.ProvisioningService; -import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.DeltaConvertor; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskBinding; -import com.evolveum.midpoint.util.MiscUtil; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; -import com.evolveum.midpoint.util.logging.LoggingUtils; -import com.evolveum.midpoint.util.logging.Trace; -import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.api.WfTaskExtensionItemsNames; -import com.evolveum.midpoint.wf.impl.WfConfiguration; -import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; -import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.aspect.PrimaryChangeAspect; -import com.evolveum.midpoint.wf.processors.primary.PcpTaskExtensionItemsNames; -import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; -import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; - -import org.apache.commons.lang.Validate; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.DependsOn; -import org.springframework.stereotype.Component; - -import javax.annotation.PostConstruct; -import javax.xml.namespace.QName; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Handles low-level task operations, e.g. handling wf* properties in task extension. - * - * @author mederly - * - */ - -@Component -@DependsOn({ "prismContext" }) - -public class WfTaskUtil { - - @Autowired - private WfConfiguration wfConfiguration; - - @Autowired - @Qualifier("cacheRepositoryService") - private RepositoryService repositoryService; - - @Autowired - private PrismContext prismContext; - - @Autowired - private ProvisioningService provisioningService; - - private static final Trace LOGGER = TraceManager.getTrace(WfTaskUtil.class); - - public static final String WAIT_FOR_TASKS_HANDLER_URI = "<<< marker for calling pushWaitForTasksHandlerUri >>>"; - - // workflow-related extension properties - private PrismPropertyDefinition wfStatusPropertyDefinition; - private PrismPropertyDefinition wfLastDetailsPropertyDefinition; - private PrismPropertyDefinition wfLastVariablesPropertyDefinition; - private PrismPropertyDefinition wfPrimaryChangeAspectPropertyDefinition; - private PrismPropertyDefinition wfChangeProcessorPropertyDefinition; - private PrismPropertyDefinition wfProcessIdPropertyDefinition; - private PrismPropertyDefinition wfDeltasToProcessPropertyDefinition; - private PrismPropertyDefinition wfResultingDeltasPropertyDefinition; - private PrismPropertyDefinition wfProcessInstanceFinishedPropertyDefinition; - private PrismPropertyDefinition wfRootTaskOidPropertyDefinition; - private PrismReferenceDefinition wfApprovedByReferenceDefinition; - - @PostConstruct - public void init() { - - wfStatusPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(WfTaskExtensionItemsNames.WFSTATUS_PROPERTY_NAME); - wfLastDetailsPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(WfTaskExtensionItemsNames.WFLAST_DETAILS_PROPERTY_NAME); - wfLastVariablesPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(WfTaskExtensionItemsNames.WFLAST_VARIABLES_PROPERTY_NAME); - wfPrimaryChangeAspectPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(PcpTaskExtensionItemsNames.WFPRIMARY_CHANGE_ASPECT_NAME); - wfChangeProcessorPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(WfTaskExtensionItemsNames.WFCHANGE_PROCESSOR_PROPERTY_NAME); - wfProcessIdPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(WfTaskExtensionItemsNames.WFPROCESSID_PROPERTY_NAME); - wfDeltasToProcessPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(PcpTaskExtensionItemsNames.WFDELTAS_TO_PROCESS_PROPERTY_NAME); - wfResultingDeltasPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(PcpTaskExtensionItemsNames.WFRESULTING_DELTAS_PROPERTY_NAME); - wfProcessInstanceFinishedPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(WfTaskExtensionItemsNames.WFPROCESS_INSTANCE_FINISHED_PROPERTY_NAME); - wfRootTaskOidPropertyDefinition = prismContext.getSchemaRegistry().findPropertyDefinitionByElementName(WfTaskExtensionItemsNames.WFROOT_TASK_OID_PROPERTY_NAME); - wfApprovedByReferenceDefinition = prismContext.getSchemaRegistry().findReferenceDefinitionByElementName(PcpTaskExtensionItemsNames.WFAPPROVED_BY_REFERENCE_NAME); - - Validate.notNull(wfStatusPropertyDefinition, WfTaskExtensionItemsNames.WFSTATUS_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfLastDetailsPropertyDefinition, WfTaskExtensionItemsNames.WFLAST_DETAILS_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfLastVariablesPropertyDefinition, WfTaskExtensionItemsNames.WFLAST_VARIABLES_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfPrimaryChangeAspectPropertyDefinition, PcpTaskExtensionItemsNames.WFPRIMARY_CHANGE_ASPECT_NAME + " definition was not found"); - Validate.notNull(wfChangeProcessorPropertyDefinition, WfTaskExtensionItemsNames.WFCHANGE_PROCESSOR_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfProcessIdPropertyDefinition, WfTaskExtensionItemsNames.WFPROCESSID_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfDeltasToProcessPropertyDefinition, PcpTaskExtensionItemsNames.WFDELTAS_TO_PROCESS_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfResultingDeltasPropertyDefinition, PcpTaskExtensionItemsNames.WFRESULTING_DELTAS_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfProcessInstanceFinishedPropertyDefinition, WfTaskExtensionItemsNames.WFPROCESS_INSTANCE_FINISHED_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfRootTaskOidPropertyDefinition, WfTaskExtensionItemsNames.WFROOT_TASK_OID_PROPERTY_NAME + " definition was not found"); - Validate.notNull(wfApprovedByReferenceDefinition, PcpTaskExtensionItemsNames.WFAPPROVED_BY_REFERENCE_NAME + " definition was not found"); - - if (wfLastVariablesPropertyDefinition.isIndexed() != Boolean.FALSE) { - throw new SystemException("lastVariables property isIndexed attribute is incorrect (should be FALSE, it is " + wfLastVariablesPropertyDefinition.isIndexed() + ")"); - } - if (wfLastDetailsPropertyDefinition.isIndexed() != Boolean.FALSE) { - throw new SystemException("lastDetails property isIndexed attribute is incorrect (should be FALSE, it is " + wfLastDetailsPropertyDefinition.isIndexed() + ")"); - } - - } - - void setWfProcessIdImmediate(Task task, String pid, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - String oid = task.getOid(); - Validate.notEmpty(oid, "Task oid must not be null or empty (task must be persistent)."); - setExtensionPropertyImmediate(task, wfProcessIdPropertyDefinition, pid, parentResult); - } - - String getLastVariables(Task task) { - PrismProperty p = task.getExtensionProperty(WfTaskExtensionItemsNames.WFLAST_VARIABLES_PROPERTY_NAME); - if (p == null) { - return null; - } else { - return p.getValue(String.class).getValue(); - } - } - - String getLastDetails(Task task) { - PrismProperty p = task.getExtensionProperty(WfTaskExtensionItemsNames.WFLAST_DETAILS_PROPERTY_NAME); - if (p == null) { - return null; - } else { - return p.getValue(String.class).getValue(); - } - } - - /** - * Sets an extension property. - */ - private void setExtensionPropertyImmediate(Task task, PrismPropertyDefinition propertyDef, T propertyValue, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - if (parentResult == null) - parentResult = new OperationResult("setExtensionPropertyImmediate"); - - PrismProperty prop = propertyDef.instantiate(); - prop.setValue(new PrismPropertyValue(propertyValue)); - - try { - task.setExtensionPropertyImmediate(prop, parentResult); - } catch (ObjectNotFoundException ex) { - parentResult.recordFatalError("Object not found", ex); - LoggingUtils.logException(LOGGER, "Cannot set {} for task {}", ex, propertyDef.getName(), task); - throw ex; - } catch (SchemaException ex) { - parentResult.recordFatalError("Schema error", ex); - LoggingUtils.logException(LOGGER, "Cannot set {} for task {}", ex, propertyDef.getName(), task); - throw ex; - } catch (RuntimeException ex) { - parentResult.recordFatalError("Internal error", ex); - LoggingUtils.logException(LOGGER, "Cannot set {} for task {}", ex, propertyDef.getName(), task); - throw ex; - } - - } - - private void setExtensionProperty(Task task, PrismPropertyDefinition propertyDef, T propertyValue, OperationResult parentResult) throws SchemaException, ObjectNotFoundException { - if (parentResult == null) - parentResult = new OperationResult("setExtensionProperty"); - - PrismProperty prop = propertyDef.instantiate(); - prop.setValue(new PrismPropertyValue(propertyValue)); - - try { - task.setExtensionProperty(prop); - } catch (SchemaException ex) { - parentResult.recordFatalError("Schema error", ex); - LoggingUtils.logException(LOGGER, "Cannot set {} for task {}", ex, propertyDef.getName(), task); - throw ex; - } catch (RuntimeException ex) { - parentResult.recordFatalError("Internal error", ex); - LoggingUtils.logException(LOGGER, "Cannot set {} for task {}", ex, propertyDef.getName(), task); - throw ex; - } - - } - - public void setPrimaryChangeAspect(Task task, PrimaryChangeAspect aspect) throws SchemaException { - Validate.notNull(aspect, "Primary change aspect is undefined."); - PrismProperty w = wfPrimaryChangeAspectPropertyDefinition.instantiate(); - w.setRealValue(aspect.getClass().getName()); - task.setExtensionProperty(w); - } - - public PrimaryChangeAspect getPrimaryChangeAspect(Task task, Collection aspects) { - String aspectClassName = getExtensionValue(String.class, task, PcpTaskExtensionItemsNames.WFPRIMARY_CHANGE_ASPECT_NAME); - if (aspectClassName == null) { - throw new IllegalStateException("No wf primary change aspect defined in task " + task); - } - - for (PrimaryChangeAspect a : aspects) { - if (aspectClassName.equals(a.getClass().getName())) { - return a; - } - } - - throw new IllegalStateException("Primary change aspect " + aspectClassName + " is not registered."); - } - - public void setChangeProcessor(Task task, ChangeProcessor processor) throws SchemaException { - Validate.notNull(processor, "Change processor is undefined."); - PrismProperty w = wfChangeProcessorPropertyDefinition.instantiate(); - w.setRealValue(processor.getClass().getName()); - task.setExtensionProperty(w); - } - - public ChangeProcessor getChangeProcessor(Task task) { - String processorClassName = getExtensionValue(String.class, task, WfTaskExtensionItemsNames.WFCHANGE_PROCESSOR_PROPERTY_NAME); - if (processorClassName == null) { - throw new IllegalStateException("No change processor defined in task " + task); - } - return wfConfiguration.findChangeProcessor(processorClassName); - } - - - public String getProcessId(Task task) { - // let us request the current task status - // todo make this property single-valued in schema to be able to use getRealValue - PrismProperty idProp = task.getExtensionProperty(WfTaskExtensionItemsNames.WFPROCESSID_PROPERTY_NAME); - Collection values = null; - if (idProp != null) { - values = idProp.getRealValues(String.class); - } - if (values == null || values.isEmpty()) { - return null; - } else { - return values.iterator().next(); - } - } - - public boolean hasModelContext(Task task) { - return task.getModelOperationContext() != null; - } - - public ModelContext retrieveModelContext(Task task, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException { - LensContextType modelContextType = task.getModelOperationContext(); - if (modelContextType == null) { -// throw new SystemException("No model context information in task " + task); - return null; - } -// Object value = modelContextProperty.getRealValue(); -// if (value instanceof Element || value instanceof JAXBElement) { -// value = prismContext.getPrismJaxbProcessor().unmarshalObject(value, LensContextType.class); -// } -// if (!(value instanceof LensContextType)) { -// throw new SystemException("Model context information in task " + task + " is of wrong type: " + modelContextProperty.getRealValue().getClass()); -// } - return LensContext.fromLensContextType(modelContextType, prismContext, provisioningService, result); - } - - public void storeModelContext(Task task, ModelContext context) throws SchemaException { - //Validate.notNull(context, "model context cannot be null"); - LensContextType modelContext = context != null ? ((LensContext) context).toLensContextType() : null; - storeModelContext(task, modelContext); - } - - public void storeModelContext(Task task, LensContextType context) throws SchemaException { - task.setModelOperationContext(context); - } - - public void storeResultingDeltas(ObjectTreeDeltas deltas, Task task) throws SchemaException { - PrismProperty resultingDeltas = wfResultingDeltasPropertyDefinition.instantiate(); - ObjectTreeDeltasType deltasType = ObjectTreeDeltas.toObjectTreeDeltasType(deltas); - resultingDeltas.setRealValue(deltasType); - task.setExtensionProperty(resultingDeltas); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Stored deltas into task {}:\n{}", task, deltas); // TODO debug dump - } - } - - public ObjectTreeDeltas retrieveDeltasToProcess(Task task) throws SchemaException { - - PrismProperty deltaTypePrismProperty = task.getExtensionProperty(PcpTaskExtensionItemsNames.WFDELTAS_TO_PROCESS_PROPERTY_NAME); - if (deltaTypePrismProperty == null) { - throw new SchemaException("No " + PcpTaskExtensionItemsNames.WFDELTAS_TO_PROCESS_PROPERTY_NAME + " in task extension; task = " + task); - } - return ObjectTreeDeltas.fromObjectTreeDeltasType(deltaTypePrismProperty.getRealValue(), prismContext); - } - - // it is possible that resulting deltas are not in the task - public ObjectTreeDeltas retrieveResultingDeltas(Task task) throws SchemaException { - PrismProperty deltaTypePrismProperty = task.getExtensionProperty(PcpTaskExtensionItemsNames.WFRESULTING_DELTAS_PROPERTY_NAME); - if (deltaTypePrismProperty == null) { - return null; - } - return ObjectTreeDeltas.fromObjectTreeDeltasType(deltaTypePrismProperty.getRealValue(), prismContext); - } - - public void setTaskNameIfEmpty(Task t, PolyStringType taskName) { - if (t.getName() == null || t.getName().toPolyString().isEmpty()) { - t.setName(taskName); - } - } - - - public void setWfLastVariables(Task task, String value) throws SchemaException { - PrismProperty wfLastVariablesProperty = wfLastVariablesPropertyDefinition.instantiate(); - wfLastVariablesProperty.setValue(new PrismPropertyValue(value)); - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("WfLastVariable INDEXED = " + wfLastVariablesProperty.getDefinition().isIndexed()); - } - task.setExtensionProperty(wfLastVariablesProperty); - - } - - public void addWfStatus(Task task, String value) throws SchemaException { - PrismProperty wfStatusProperty = wfStatusPropertyDefinition.instantiate(); - PrismPropertyValue newValue = new PrismPropertyValue(value); - wfStatusProperty.addValue(newValue); - task.addExtensionProperty(wfStatusProperty); - } - - private T getExtensionValue(Class clazz, Task task, QName propertyName) { - PrismProperty property = task.getExtensionProperty(propertyName); - return property != null ? property.getRealValue(clazz) : null; - } - - public void setProcessInstanceFinishedImmediate(Task task, Boolean value, OperationResult result) throws SchemaException, ObjectNotFoundException { - setExtensionPropertyImmediate(task, wfProcessInstanceFinishedPropertyDefinition, value, result); - } - - public boolean isProcessInstanceFinished(Task task) { - Boolean value = getExtensionValue(Boolean.class, task, WfTaskExtensionItemsNames.WFPROCESS_INSTANCE_FINISHED_PROPERTY_NAME); - return value != null ? value : false; - } - - public void setRootTaskOidImmediate(Task task, String value, OperationResult result) throws SchemaException, ObjectNotFoundException { - setExtensionPropertyImmediate(task, wfRootTaskOidPropertyDefinition, value, result); - } - - public String getRootTaskOid(Task task) { - return getExtensionValue(String.class, task, WfTaskExtensionItemsNames.WFROOT_TASK_OID_PROPERTY_NAME); - } - - public void deleteModelOperationContext(Task task, OperationResult result) throws SchemaException, ObjectNotFoundException { - task.setModelOperationContext(null); - } - - public void setLastDetails(Task task, String status) throws SchemaException { - PrismProperty wfLastDetailsProperty = wfLastDetailsPropertyDefinition.instantiate(); - PrismPropertyValue newValue = new PrismPropertyValue(status); - wfLastDetailsProperty.setValue(newValue); - task.setExtensionProperty(wfLastDetailsProperty); - } - - public void addApprovedBy(Task task, ObjectReferenceType referenceType) throws SchemaException { - PrismReference wfApprovedBy = wfApprovedByReferenceDefinition.instantiate(); - PrismReferenceValue newValue = new PrismReferenceValue(referenceType.getOid()); - wfApprovedBy.add(newValue); - task.addExtensionReference(wfApprovedBy); - } - - public void addApprovedBy(Task task, Collection referenceTypes) throws SchemaException { - PrismReference wfApprovedBy = wfApprovedByReferenceDefinition.instantiate(); - for (ObjectReferenceType referenceType : referenceTypes) { - wfApprovedBy.add(referenceType.asReferenceValue().clone()); - } - task.addExtensionReference(wfApprovedBy); - } - - public void addApprovedBy(Task task, String oid) throws SchemaException { - ObjectReferenceType objectReferenceType = new ObjectReferenceType(); - objectReferenceType.setOid(oid); - addApprovedBy(task, objectReferenceType); - } - - public PrismReference getApprovedBy(Task task) throws SchemaException { - return task.getExtensionReference(PcpTaskExtensionItemsNames.WFAPPROVED_BY_REFERENCE_NAME); - } - - public List getApprovedByFromTaskTree(Task task, OperationResult result) throws SchemaException { - // we use a OID-keyed map to (1) keep not only the OID, but whole reference, but (2) eliminate uncertainty in comparing references - Map approvers = new HashMap<>(); - - List tasks = task.listSubtasksDeeply(result); - tasks.add(task); - for (Task aTask : tasks) { - PrismReference approvedBy = getApprovedBy(aTask); - if (approvedBy != null) { - for (PrismReferenceValue referenceValue : approvedBy.getValues()) { - approvers.put(referenceValue.getOid(), referenceValue); - } - } - } - - List retval = new ArrayList<>(approvers.size()); - for (PrismReferenceValue approverRefValue : approvers.values()) { - ObjectReferenceType referenceType = new ObjectReferenceType(); - referenceType.setupReferenceValue(approverRefValue.clone()); - retval.add(referenceType); - } - return retval; - } - - public PrismPropertyDefinition getWfStatusPropertyDefinition() { - return wfStatusPropertyDefinition; - } - - public PrismPropertyDefinition getWfLastDetailsPropertyDefinition() { - return wfLastDetailsPropertyDefinition; - } - - public PrismPropertyDefinition getWfLastVariablesPropertyDefinition() { - return wfLastVariablesPropertyDefinition; - } - - public PrismPropertyDefinition getWfPrimaryChangeAspectPropertyDefinition() { - return wfPrimaryChangeAspectPropertyDefinition; - } - - public PrismPropertyDefinition getWfChangeProcessorPropertyDefinition() { - return wfChangeProcessorPropertyDefinition; - } - - public PrismPropertyDefinition getWfProcessIdPropertyDefinition() { - return wfProcessIdPropertyDefinition; - } - - public PrismPropertyDefinition getWfDeltasToProcessPropertyDefinition() { - return wfDeltasToProcessPropertyDefinition; - } - - public PrismPropertyDefinition getWfResultingDeltasPropertyDefinition() { - return wfResultingDeltasPropertyDefinition; - } - - public PrismPropertyDefinition getWfProcessInstanceFinishedPropertyDefinition() { - return wfProcessInstanceFinishedPropertyDefinition; - } - - public PrismReferenceDefinition getWfApprovedByReferenceDefinition() { - return wfApprovedByReferenceDefinition; - } - - void setTaskOwner(Task task, PrismObject owner) { - if (owner == null) { - throw new IllegalStateException("Couldn't create a job task because the owner is not set."); - } - task.setOwner(owner); - } - - // handlers are stored in the list in the order they should be executed; so the last one has to be pushed first - void pushHandlers(Task task, List handlers) { - for (int i = handlers.size()-1; i >= 0; i--) { - UriStackEntry entry = handlers.get(i); - if (WAIT_FOR_TASKS_HANDLER_URI.equals(entry.getHandlerUri())) { - task.pushWaitForTasksHandlerUri(); - } else { - if (!entry.getExtensionDelta().isEmpty()) { - throw new UnsupportedOperationException("handlers with extension delta set are not supported yet"); - } - task.pushHandlerUri(entry.getHandlerUri(), entry.getSchedule(), TaskBinding.fromTaskType(entry.getBinding()), (ItemDelta) null); - } - } - } - - /** - * Makes a task active, i.e. a task that actively queries wf process instance about its status. - * - * OR - * - * Creates a passive task, i.e. a task that stores information received from WfMS about a process instance. - * - * We expect task to be transient at this moment! - * @param active - * @param t - * @param result - */ - void pushProcessShadowHandler(boolean active, Task t, long taskStartDelay, OperationResult result) throws SchemaException, ObjectNotFoundException { - - if (active) { - - ScheduleType schedule = new ScheduleType(); - schedule.setInterval(wfConfiguration.getProcessCheckInterval()); - schedule.setEarliestStartTime(MiscUtil.asXMLGregorianCalendar(new Date(System.currentTimeMillis() + taskStartDelay))); - t.pushHandlerUri(WfProcessInstanceShadowTaskHandler.HANDLER_URI, schedule, TaskBinding.LOOSE); - - } else { - - t.pushHandlerUri(WfProcessInstanceShadowTaskHandler.HANDLER_URI, new ScheduleType(), null); // note that this handler will not be actively used (at least for now) - t.makeWaiting(); - } - } - - void setDefaultTaskOwnerIfEmpty(Task t, OperationResult result, JobController jobController) throws SchemaException, ObjectNotFoundException { - if (t.getOwner() == null) { - t.setOwner(repositoryService.getObject(UserType.class, SystemObjectsType.USER_ADMINISTRATOR.value(), null, result)); - } - } -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ActivitiToMidPointMessage.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ActivitiToMidPointMessage.java deleted file mode 100644 index ec61b0487ac..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ActivitiToMidPointMessage.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.messages; - -/** - * Created with IntelliJ IDEA. - * User: mederly - * Date: 28.7.2012 - * Time: 17:08 - * To change this template use File | Settings | File Templates. - */ -public class ActivitiToMidPointMessage { -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/MidPointToActivitiMessage.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/MidPointToActivitiMessage.java deleted file mode 100644 index 2cf33500c0c..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/MidPointToActivitiMessage.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.messages; - -/** - * Created with IntelliJ IDEA. - * User: mederly - * Date: 28.7.2012 - * Time: 16:30 - * To change this template use File | Settings | File Templates. - */ -public class MidPointToActivitiMessage { -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessEvent.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessEvent.java index 300921eaa61..23e96318484 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessEvent.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessEvent.java @@ -16,7 +16,11 @@ package com.evolveum.midpoint.wf.impl.messages; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; +import com.evolveum.midpoint.wf.impl.processes.ProcessMidPointInterface; import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; +import org.activiti.engine.delegate.DelegateExecution; import java.util.HashMap; import java.util.Map; @@ -24,70 +28,58 @@ /** * Process instance event - signals that something has happened with process instance. */ -public class ProcessEvent extends ActivitiToMidPointMessage { +public class ProcessEvent { /** * Workflow process instance variables. */ - private Map variables = new HashMap(); + private final Map variables = new HashMap<>(); /** * Workflow process instance ID. */ - private String pid; - - /** - * MidPoint monitoring task OID. - */ - private String taskOid; + private final String pid; /** * Is the process still running? */ private boolean running; - /** - * What is a (textually characterized) state of the process instance? - */ - private String state; - - /** - * What is a (textually characterized) final answer? - */ private String answer; - - public String getPid() { + private String state; + + public ProcessEvent(DelegateExecution execution, ProcessInterfaceFinder processInterfaceFinder) { + pid = execution.getProcessInstanceId(); + running = true; + addVariablesFrom(execution.getVariables()); + computeStateAndAnswer(processInterfaceFinder); + } + + private void computeStateAndAnswer(ProcessInterfaceFinder processInterfaceFinder) { + ProcessMidPointInterface pmi = processInterfaceFinder.getProcessInterface(variables); + state = pmi.getState(variables); + answer = pmi.getAnswer(variables); + } + + public ProcessEvent(String pid, Map variables, ProcessInterfaceFinder processInterfaceFinder) { + this.pid = pid; + addVariablesFrom(variables); + computeStateAndAnswer(processInterfaceFinder); + } + + public String getPid() { return pid; } - public void setPid(String pid) { - this.pid = pid; - } - - public String getTaskOid() { - return taskOid; - } - - public void setTaskOid(String taskOid) { - this.taskOid = taskOid; - } - public Map getVariables() { return variables; } - public Object getVariable(String name) { - return variables.get(name); - } - - public void setVariables(Map variables) { - this.variables = variables; + public T getVariable(String name, Class clazz) { + return (T) variables.get(name); } public void putVariable(String name, Object value) { - if (variables == null) { - variables = new HashMap(); - } variables.put(name, value); } @@ -99,13 +91,29 @@ public void setRunning(boolean running) { this.running = running; } - public void setVariablesFrom(Map map) { - variables = new HashMap(map); + public void addVariablesFrom(Map map) { + variables.putAll(map); } - @Override + public String getAnswer() { + return answer; + } + + public void setAnswer(String answer) { + this.answer = answer; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + @Override public String toString() { - return this.getClass().getSimpleName() + "[pid=" + pid + ", running=" + running + ", task=" + taskOid + ", variables=" + variables + "]"; + return this.getClass().getSimpleName() + "[pid=" + pid + ", running=" + running + ", variables=" + variables + "]"; } public boolean containsVariable(String varname) { @@ -116,19 +124,7 @@ public boolean containsVariable(String varname) { } } - public String getState() { - return state; - } - - public void setState(String state) { - this.state = state; - } - - public String getAnswer() { - return answer; - } - - public void setAnswer(String answer) { - this.answer = answer; - } + public String getProcessDebugInfo() { + return "pid=" + pid + ", name=" + getVariable(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME, String.class); + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessFinishedEvent.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessFinishedEvent.java index 4539fad36d2..bfb5d78ae87 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessFinishedEvent.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessFinishedEvent.java @@ -16,6 +16,9 @@ package com.evolveum.midpoint.wf.impl.messages; +import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; +import org.activiti.engine.delegate.DelegateExecution; + /** * Created with IntelliJ IDEA. * User: mederly @@ -25,4 +28,8 @@ */ public class ProcessFinishedEvent extends ProcessEvent { + public ProcessFinishedEvent(DelegateExecution execution, ProcessInterfaceFinder processInterfaceFinder) { + super(execution, processInterfaceFinder); + setRunning(false); + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessStartedEvent.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessStartedEvent.java index e15bc493884..bf4277feabb 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessStartedEvent.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/ProcessStartedEvent.java @@ -16,6 +16,11 @@ package com.evolveum.midpoint.wf.impl.messages; +import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; +import org.activiti.engine.delegate.DelegateExecution; + +import java.util.Map; + /** * Created with IntelliJ IDEA. * User: mederly @@ -25,4 +30,7 @@ */ public class ProcessStartedEvent extends ProcessEvent { + public ProcessStartedEvent(String pid, Map variables, ProcessInterfaceFinder processInterfaceFinder) { + super(pid, variables, processInterfaceFinder); + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/QueryProcessCommand.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/QueryProcessCommand.java index fbbd0b495fa..65c542f4635 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/QueryProcessCommand.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/QueryProcessCommand.java @@ -19,7 +19,7 @@ /** * Command to query a process instance. */ -public class QueryProcessCommand extends MidPointToActivitiMessage { +public class QueryProcessCommand { private String pid; private String taskOid; diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/QueryProcessResponse.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/QueryProcessResponse.java index fa5fb6afbc2..7c37c20db0d 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/QueryProcessResponse.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/QueryProcessResponse.java @@ -16,9 +16,16 @@ package com.evolveum.midpoint.wf.impl.messages; +import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; + +import java.util.Map; + /** * @author mederly */ public class QueryProcessResponse extends ProcessEvent { + public QueryProcessResponse(String pid, Map variables, ProcessInterfaceFinder processInterfaceFinder) { + super(pid, variables, processInterfaceFinder); + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/StartProcessCommand.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/StartProcessCommand.java index 9b40de55e62..ea6a8a2819f 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/StartProcessCommand.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/StartProcessCommand.java @@ -22,12 +22,12 @@ /** * Command to start process instance. */ -public class StartProcessCommand extends MidPointToActivitiMessage { +public class StartProcessCommand { private Map variables; private String processName; + private String processInstanceName; private String processOwner; - private String taskOid; private boolean sendStartConfirmation; public String getProcessName() { @@ -38,20 +38,20 @@ public void setProcessName(String processName) { this.processName = processName; } - public boolean isSendStartConfirmation() { - return sendStartConfirmation; + public String getProcessInstanceName() { + return processInstanceName; } - public void setSendStartConfirmation(boolean sendStartConfirmation) { - this.sendStartConfirmation = sendStartConfirmation; + public void setProcessInstanceName(String processInstanceName) { + this.processInstanceName = processInstanceName; } - public String getTaskOid() { - return taskOid; + public boolean isSendStartConfirmation() { + return sendStartConfirmation; } - public void setTaskOid(String taskOid) { - this.taskOid = taskOid; + public void setSendStartConfirmation(boolean sendStartConfirmation) { + this.sendStartConfirmation = sendStartConfirmation; } public Map getVariables() { @@ -63,7 +63,7 @@ public void setVariables(Map variables) { } public void setVariablesFrom(Map variables) { - this.variables = new HashMap(variables); + this.variables = new HashMap<>(variables); } public void addVariable(String name, Object value) { @@ -83,6 +83,6 @@ public void setProcessOwner(String processOwner) { @Override public String toString() { - return this.getClass().getSimpleName() + "[process=" + processName + ", task=" + taskOid + ", variables=" + variables + ", sendStartConfirmation=" + sendStartConfirmation + "]"; + return this.getClass().getSimpleName() + "[process=" + processName + "/" + processInstanceName + ", variables=" + variables + ", sendStartConfirmation=" + sendStartConfirmation + "]"; } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/TaskEvent.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/TaskEvent.java index 8457ab23695..4bbe0476be2 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/TaskEvent.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/messages/TaskEvent.java @@ -31,7 +31,7 @@ * * @author mederly */ -public class TaskEvent extends ActivitiToMidPointMessage { +public class TaskEvent { /** * Workflow process instance variables, merged with form properties (TODO: verify this). diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/DefaultProcessMidPointInterface.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/DefaultProcessMidPointInterface.java index b39d8a3fc97..18d961d7d3a 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/DefaultProcessMidPointInterface.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/DefaultProcessMidPointInterface.java @@ -17,10 +17,9 @@ package com.evolveum.midpoint.wf.impl.processes; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; +import com.evolveum.midpoint.xml.ns._public.common.common_3.DecisionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; -import com.sun.corba.se.spi.ior.iiop.ORBTypeComponent; - +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessSpecificStateType; import org.springframework.stereotype.Component; import java.util.ArrayList; @@ -36,7 +35,11 @@ public class DefaultProcessMidPointInterface extends BaseProcessMidPointInterface { @Override - public ProcessSpecificState externalizeProcessInstanceState(Map variables) { + public WfProcessSpecificStateType externalizeProcessSpecificState(Map variables) { + return null; + } + + @Override public DecisionType extractDecision(Map variables) { return null; } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/ProcessInterfaceFinder.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/ProcessInterfaceFinder.java index a8354e69211..8a7a7f213b8 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/ProcessInterfaceFinder.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/ProcessInterfaceFinder.java @@ -34,9 +34,9 @@ public class ProcessInterfaceFinder implements BeanFactoryAware { private BeanFactory beanFactory; public ProcessMidPointInterface getProcessInterface(Map variables) { - String interfaceBeanName = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_PROCESS_INTERFACE_BEAN_NAME); + String interfaceBeanName = (String) variables.get(CommonProcessVariableNames.VARIABLE_PROCESS_INTERFACE_BEAN_NAME); if (interfaceBeanName == null) { - throw new IllegalStateException("No " + CommonProcessVariableNames.VARIABLE_MIDPOINT_PROCESS_INTERFACE_BEAN_NAME + " variable found"); + throw new IllegalStateException("No " + CommonProcessVariableNames.VARIABLE_PROCESS_INTERFACE_BEAN_NAME + " variable found"); } return beanFactory.getBean(interfaceBeanName, ProcessMidPointInterface.class); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/ProcessMidPointInterface.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/ProcessMidPointInterface.java index 98c88519f8a..14004658e3a 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/ProcessMidPointInterface.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/ProcessMidPointInterface.java @@ -17,8 +17,9 @@ package com.evolveum.midpoint.wf.impl.processes; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; +import com.evolveum.midpoint.xml.ns._public.common.common_3.DecisionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessSpecificStateType; import java.util.List; import java.util.Map; @@ -32,9 +33,11 @@ public interface ProcessMidPointInterface { String getState(Map variables); - ProcessSpecificState externalizeProcessInstanceState(Map variables); + WfProcessSpecificStateType externalizeProcessSpecificState(Map variables); + + DecisionType extractDecision(Map variables); String getBeanName(); List prepareApprovedBy(ProcessEvent event); -} +} \ No newline at end of file diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/ActivitiUtil.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/ActivitiUtil.java index 088bf197934..fa800e7d836 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/ActivitiUtil.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/ActivitiUtil.java @@ -18,13 +18,21 @@ import com.evolveum.midpoint.model.api.expr.MidpointFunctions; import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.impl.util.SerializationSafeContainer; import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; +import org.activiti.engine.delegate.DelegateExecution; import java.io.Serializable; +import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.*; + /** * General utilities that can be used from within processes. * @@ -64,11 +72,24 @@ public void revive(SerializationSafeContainer container) { // todo - better name? public MidpointFunctions midpoint() { - return SpringApplicationContextHolder.getMidpointFunctions(); + return getMidpointFunctions(); } @Override public String toString() { return this.getClass().getName() + " object."; } + + public static Task getTask(DelegateExecution execution, OperationResult result) { + String oid = execution.getVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID, String.class); + if (oid == null) { + throw new IllegalStateException("No task OID in process " + execution.getProcessInstanceId()); + } + + try { + return getTaskManager().getTask(oid, result); + } catch (ObjectNotFoundException|SchemaException|RuntimeException e) { + throw new SystemException("Couldn't get task " + oid + " corresponding to process " + execution.getProcessInstanceId(), e); + } + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/CommonProcessVariableNames.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/CommonProcessVariableNames.java index a475021b4e2..90a67e46ad3 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/CommonProcessVariableNames.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/CommonProcessVariableNames.java @@ -21,48 +21,57 @@ */ public class CommonProcessVariableNames { - // Process instance name, e.g. "Approving adding Webmaster to JoeDoe". [String] + // [String] + // Process instance name, e.g. "Approving adding Webmaster to JoeDoe". + // Used for diagnostic purposes. public static final String VARIABLE_PROCESS_INSTANCE_NAME = "processInstanceName"; - // When the process instance was started. [java.util.Date] + // [java.util.Date] + // When the process instance was started. public static final String VARIABLE_START_TIME = "startTime"; - // OID of task related to the process instance. [String] + // [String] + // OID of task related to the process instance. public static final String VARIABLE_MIDPOINT_TASK_OID = "midPointTaskOid"; - // Java class name of the change processor (the same as wf:changeProcessor task property) [String] - public static final String VARIABLE_MIDPOINT_CHANGE_PROCESSOR = "midPointChangeProcessor"; + // [String] + // Java class name of the change processor (the same as wf:changeProcessor task property) + public static final String VARIABLE_CHANGE_PROCESSOR = "changeProcessor"; - // OID of the user who requested the particular operation (e.g. adding of a role to another user). - // Used e.g. for searching for process instances requested by particular user. [String] - public static final String VARIABLE_MIDPOINT_REQUESTER_OID = "midPointRequesterOid"; + // [LightweightObjectRef] + // Requester - OID + name + perhaps additional information + public static final String VARIABLE_REQUESTER_REF = "requesterRef"; - // OID of the object (typically, a user) that is being changed within the operation. [String] - // In some cases (e.g. for PrimaryChangeProcessor) the OID is determined clearly. - // In other situations, e.g. for GeneralChangeProcessor there must be a code that provides - // this information. In some cases, there may be no OID - e.g. when an object is yet to be created. - // - // TODO think about storing also object class (currently we fetch an object from the repo as "ObjectType.class" but that's far from ideal). - public static final String VARIABLE_MIDPOINT_OBJECT_OID = "midPointObjectOid"; + // [LightweightObjectRef] + // Object of the operation - if can be specified like this + public static final String VARIABLE_OBJECT_REF = "objectRef"; - // Object that provides various utility methods for use in processes, e.g. getApprover(RoleType r). [ActivitiUtil] - public static final String VARIABLE_UTIL = "util"; + // [LightweightObjectRef] + // Target of the operation - if any + public static final String VARIABLE_TARGET_REF = "targetRef"; - // Basic decision returned from a work item. - // for most work items it is simple __APPROVED__ or __REJECTED__, but in principle this can be any string value - public static final String FORM_FIELD_DECISION = "[H]decision"; + // [Boolean] + // A signal that the process instance is being stopped. Used e.g. to suppress propagation of exceptions + // occurring in the process instance end listener. + public static final String VARIABLE_PROCESS_INSTANCE_IS_STOPPING = "processInstanceIsStopping"; - // Comment related to that decision - set by user task (form). [String] - // this value is put into audit record, so its advisable to use this particular name - public static final String FORM_FIELD_COMMENT = "comment"; + // [String] + // Name of process interface bean (ProcessMidPointInterface implementation) that is related to this process + public static final String VARIABLE_PROCESS_INTERFACE_BEAN_NAME = "processInterfaceBeanName"; - public static final String FORM_BUTTON_PREFIX = "[B]"; + // [ActivitiUtil] + // Object that provides various utility methods for use in processes, e.g. getApprover(RoleType r). + public static final String VARIABLE_UTIL = "util"; - // A signal that the process instance is being stopped. Used e.g. to suppress propagation of exceptions - // occurring in the process instance end listener. - // [Boolean] - public static final String VARIABLE_MIDPOINT_IS_PROCESS_INSTANCE_STOPPING = "midPointIsProcessInstanceStopping"; + // [String] + // Basic decision returned from a work item. + // for most work items it is simple __APPROVED__ or __REJECTED__, but in principle this can be any string value + public static final String FORM_FIELD_DECISION = "[H]decision"; + + // [String] + // Comment related to that decision - set by user task (form). + // this value is put into audit record, so its advisable to use this particular name + public static final String FORM_FIELD_COMMENT = "comment"; - // Name of process interface bean (ProcessMidPointInterface implementation) that is related to this process [String] - public static final String VARIABLE_MIDPOINT_PROCESS_INTERFACE_BEAN_NAME = "midPointProcessInterfaceBeanName"; + public static final String FORM_BUTTON_PREFIX = "[B]"; } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/LightweightObjectRef.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/LightweightObjectRef.java index c0e2cfb52dd..0adae02c744 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/LightweightObjectRef.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/LightweightObjectRef.java @@ -30,5 +30,7 @@ public interface LightweightObjectRef { String getDescription(); + String getTargetName(); + ObjectReferenceType toObjectReferenceType(); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/LightweightObjectRefImpl.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/LightweightObjectRefImpl.java index 57143bf0ea3..7c44c7a53e0 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/LightweightObjectRefImpl.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/LightweightObjectRefImpl.java @@ -19,9 +19,11 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import javax.xml.namespace.QName; - import java.io.Serializable; +import static com.evolveum.midpoint.prism.polystring.PolyString.getOrig; +import static com.evolveum.prism.xml.ns._public.types_3.PolyStringType.fromOrig; + /** * @author mederly */ @@ -31,6 +33,7 @@ public class LightweightObjectRefImpl implements LightweightObjectRef, Serializa private String oid; private QName type; private String description; + private String targetName; public LightweightObjectRefImpl(String oid, QName type, String description) { this.oid = oid; @@ -42,6 +45,7 @@ public LightweightObjectRefImpl(ObjectReferenceType objectReferenceType) { this.oid = objectReferenceType.getOid(); this.type = objectReferenceType.getType(); this.description = objectReferenceType.getDescription(); + this.targetName = getOrig(objectReferenceType.getTargetName()); } public LightweightObjectRefImpl(String value) { @@ -75,11 +79,20 @@ public void setDescription(String description) { this.description = description; } + @Override public String getTargetName() { + return targetName; + } + + public void setTargetName(String targetName) { + this.targetName = targetName; + } + public ObjectReferenceType toObjectReferenceType() { ObjectReferenceType retval = new ObjectReferenceType(); retval.setOid(oid); retval.setDescription(description); retval.setType(type); + retval.setTargetName(fromOrig(targetName)); return retval; } @@ -87,6 +100,7 @@ public ObjectReferenceType toObjectReferenceType() { public String toString() { return "LightweightObjectRefImpl{" + "oid='" + oid + '\'' + + ", targetName=" + targetName + ", type=" + type + ", description='" + description + '\'' + '}'; diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/MidPointProcessListener.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/MidPointProcessListener.java index 4d356cac5c2..f102f81bf90 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/MidPointProcessListener.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/MidPointProcessListener.java @@ -21,6 +21,9 @@ import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.ExecutionListener; +import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.getActivitiInterface; +import static java.lang.Boolean.TRUE; + /** * A listener that informs midPoint about process instance end for "smart" processes. * A process must register this listener in order for it to be invoked using a construction like this (at the level of process): @@ -34,22 +37,22 @@ public class MidPointProcessListener implements ExecutionListener { private static final Trace LOGGER = TraceManager.getTrace(MidPointProcessListener.class); - //private static final String DOT_CLASS = MidPointProcessListener.class.getName() + "."; @Override - public void notify(DelegateExecution execution) throws Exception { - if (ExecutionListener.EVENTNAME_END.equals(execution.getEventName())) { - LOGGER.trace("Signalling process end; execution id = {}, current activity id = {}, current activity name = {}, instance id = {}", - new Object[] { execution.getId(), execution.getCurrentActivityId(), execution.getCurrentActivityName(), execution.getProcessInstanceId() }); - try { - SpringApplicationContextHolder.getActivitiInterface().notifyMidpointAboutProcessFinishedEvent(execution); - } catch (Exception e) { - LOGGER.trace("Got exception while processing process end event in midpoint", e); - if (Boolean.TRUE.equals(execution.getVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_IS_PROCESS_INSTANCE_STOPPING))) { - LOGGER.trace("... the process is ending anyway, so we just ignore this exception"); - } else { - throw e; - } + public void notify(DelegateExecution execution) { + if (!ExecutionListener.EVENTNAME_END.equals(execution.getEventName())) { + return; + } + LOGGER.trace("Signalling process end; execution id = {}, current activity id = {}, current activity name = {}, instance id = {}", + execution.getId(), execution.getCurrentActivityId(), execution.getCurrentActivityName(), execution.getProcessInstanceId()); + try { + getActivitiInterface().notifyMidpointAboutProcessFinishedEvent(execution); + } catch (RuntimeException e) { + LOGGER.trace("Got exception while processing process end event in midpoint", e); + if (TRUE.equals(execution.getVariable(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_IS_STOPPING))) { + LOGGER.trace("... the process is ending anyway, so we just ignore this exception"); + } else { + throw e; } } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/MidPointTaskListener.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/MidPointTaskListener.java index 857f6826285..e5baeda4950 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/MidPointTaskListener.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/MidPointTaskListener.java @@ -18,30 +18,23 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.activiti.ActivitiInterface; - import org.activiti.engine.delegate.DelegateTask; import org.activiti.engine.delegate.TaskListener; +import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.getActivitiInterface; + /** * @author mederly */ public class MidPointTaskListener implements TaskListener { private static final Trace LOGGER = TraceManager.getTrace(MidPointTaskListener.class); - private static final String DOT_CLASS = MidPointTaskListener.class.getName() + "."; @Override public void notify(DelegateTask delegateTask) { - if (LOGGER.isTraceEnabled()) { LOGGER.trace("notify called; event name = {}, name = {}", delegateTask.getEventName(), delegateTask.getName()); } - - ActivitiInterface activitiInterface = SpringApplicationContextHolder.getActivitiInterface(); - activitiInterface.notifyMidpointAboutTaskEvent(delegateTask); - + getActivitiInterface().notifyMidpointAboutTaskEvent(delegateTask); } - - } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/SpringApplicationContextHolder.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/SpringApplicationContextHolder.java index 62d8fbcbba7..33ef3f72116 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/SpringApplicationContextHolder.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/common/SpringApplicationContextHolder.java @@ -20,8 +20,9 @@ import com.evolveum.midpoint.model.api.expr.MidpointFunctions; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.repo.api.RepositoryService; +import com.evolveum.midpoint.task.api.TaskManager; import com.evolveum.midpoint.wf.impl.activiti.ActivitiInterface; -import com.evolveum.midpoint.wf.impl.jobs.JobController; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; import com.evolveum.midpoint.wf.impl.processors.primary.PcpRepoAccessHelper; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; @@ -76,8 +77,8 @@ public static PrismContext getPrismContext() { return getBean(PrismContext.class); } - public static JobController getJobController() { - return getBean(JobController.class); + public static WfTaskController getJobController() { + return getBean(WfTaskController.class); } public static AuditService getAuditService() { @@ -91,6 +92,10 @@ public static MidpointFunctions getMidpointFunctions() { public static PcpRepoAccessHelper getPcpRepoAccessHelper() { return getBean("pcpRepoAccessHelper", PcpRepoAccessHelper.class); } + + public static TaskManager getTaskManager() { + return getBean(TaskManager.class); + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ApprovalSchema.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ApprovalSchema.java index 6de85316013..ab6ad0ecf82 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ApprovalSchema.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ApprovalSchema.java @@ -37,4 +37,6 @@ public interface ApprovalSchema { void setPrismContext(PrismContext prismContext); void toApprovalSchemaType(ApprovalSchemaType approvalSchemaType); // expects empty (newly created) ApprovalSchemaType instance + + ApprovalSchemaType toApprovalSchemaType(); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ApprovalSchemaImpl.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ApprovalSchemaImpl.java index eb0206146eb..c6035067ffe 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ApprovalSchemaImpl.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ApprovalSchemaImpl.java @@ -17,7 +17,6 @@ package com.evolveum.midpoint.wf.impl.processes.itemApproval; import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.xjc.PrismForJAXBUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import java.io.Serializable; @@ -111,6 +110,12 @@ public void toApprovalSchemaType(ApprovalSchemaType approvalSchemaType) { } } + @Override public ApprovalSchemaType toApprovalSchemaType() { + ApprovalSchemaType ast = new ApprovalSchemaType(); + toApprovalSchemaType(ast); + return ast; + } + public void addLevel(ApprovalLevelImpl level) { levels.add(level); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/Decision.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/Decision.java index a56c92f411e..a8149920e56 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/Decision.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/Decision.java @@ -16,10 +16,12 @@ package com.evolveum.midpoint.wf.impl.processes.itemApproval; +import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.prism.xml.XmlTypeConverter; import com.evolveum.midpoint.xml.ns._public.common.common_3.DecisionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; import java.io.Serializable; import java.util.Date; @@ -91,9 +93,9 @@ public DecisionType toDecisionType() { ObjectReferenceType ort = new ObjectReferenceType(); ort.setOid(approverOid); ort.setType(UserType.COMPLEX_TYPE); + ort.setTargetName(new PolyStringType(approverName)); decisionType.setApproverRef(ort); } - decisionType.setApproverName(approverName); return decisionType; } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/InitializeLoopThroughApproversInLevel.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/InitializeLoopThroughApproversInLevel.java index ca3f3f871a0..b915ece9542 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/InitializeLoopThroughApproversInLevel.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/InitializeLoopThroughApproversInLevel.java @@ -34,11 +34,7 @@ import com.evolveum.midpoint.util.exception.SystemException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRef; -import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRefImpl; -import com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpProcessVariableNames; +import com.evolveum.midpoint.wf.impl.processes.common.*; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; @@ -51,6 +47,11 @@ import java.util.*; +import static com.evolveum.midpoint.schema.constants.SchemaConstants.C_OBJECT; +import static com.evolveum.midpoint.schema.constants.SchemaConstants.C_REQUESTER; +import static com.evolveum.midpoint.schema.constants.SchemaConstants.C_TARGET; +import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.*; + /** * @author mederly */ @@ -62,26 +63,25 @@ public class InitializeLoopThroughApproversInLevel implements JavaDelegate { public void execute(DelegateExecution execution) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Executing the delegate; execution = " + execution); - } + LOGGER.trace("Executing the delegate; execution = {}", execution); OperationResult result = new OperationResult("dummy"); - Task task = null; + Task wfTask = ActivitiUtil.getTask(execution, result); + Task opTask = getTaskManager().createTaskInstance(); ExpressionVariables expressionVariables = null; ApprovalLevelImpl level = (ApprovalLevelImpl) execution.getVariable(ProcessVariableNames.LEVEL); Validate.notNull(level, "Variable " + ProcessVariableNames.LEVEL + " is undefined"); - level.setPrismContext(SpringApplicationContextHolder.getPrismContext()); + level.setPrismContext(getPrismContext()); List decisionList = new ArrayList(); boolean preApproved = false; if (level.getAutomaticallyApproved() != null) { try { - expressionVariables = getDefaultVariables(execution, result); - preApproved = evaluateBooleanExpression(level.getAutomaticallyApproved(), expressionVariables, execution, task, result); + expressionVariables = getDefaultVariables(execution, wfTask, result); + preApproved = evaluateBooleanExpression(level.getAutomaticallyApproved(), expressionVariables, execution, opTask, result); if (LOGGER.isTraceEnabled()) { LOGGER.trace("Pre-approved = " + preApproved + " for level " + level); } @@ -97,8 +97,8 @@ public void execute(DelegateExecution execution) { if (!level.getApproverExpressions().isEmpty()) { try { - expressionVariables = getDefaultVariablesIfNeeded(expressionVariables, execution, result); - approverRefs.addAll(evaluateExpressions(level.getApproverExpressions(), expressionVariables, execution, task, result)); + expressionVariables = getDefaultVariablesIfNeeded(expressionVariables, execution, wfTask, result); + approverRefs.addAll(evaluateExpressions(level.getApproverExpressions(), expressionVariables, execution, opTask, result)); } catch (Exception e) { // todo throw new SystemException("Couldn't evaluate approvers expressions", e); } @@ -120,13 +120,13 @@ public void execute(DelegateExecution execution) { } execution.setVariableLocal(ProcessVariableNames.DECISIONS_IN_LEVEL, decisionList); - execution.setVariableLocal(ProcessVariableNames.APPROVERS_IN_LEVEL, new ArrayList(approverRefs)); + execution.setVariableLocal(ProcessVariableNames.APPROVERS_IN_LEVEL, new ArrayList<>(approverRefs)); execution.setVariableLocal(ProcessVariableNames.LOOP_APPROVERS_IN_LEVEL_STOP, stop); } private Collection evaluateExpressions(List approverExpressionList, ExpressionVariables expressionVariables, DelegateExecution execution, Task task, OperationResult result) throws ExpressionEvaluationException, ObjectNotFoundException, SchemaException { - List retval = new ArrayList(); + List retval = new ArrayList<>(); for (ExpressionType approverExpression : approverExpressionList) { retval.addAll(evaluateExpression(approverExpression, expressionVariables, execution, task, result)); } @@ -183,7 +183,7 @@ private boolean evaluateBooleanExpression(ExpressionType expressionType, Express private ExpressionFactory getExpressionFactory() { LOGGER.trace("Getting expressionFactory"); - ExpressionFactory ef = SpringApplicationContextHolder.getApplicationContext().getBean("expressionFactory", ExpressionFactory.class); + ExpressionFactory ef = getApplicationContext().getBean("expressionFactory", ExpressionFactory.class); if (ef == null) { throw new IllegalStateException("expressionFactory bean cannot be found"); } @@ -191,48 +191,33 @@ private ExpressionFactory getExpressionFactory() { } - private ExpressionVariables getDefaultVariablesIfNeeded(ExpressionVariables variables, DelegateExecution execution, OperationResult result) throws SchemaException, ObjectNotFoundException { + private ExpressionVariables getDefaultVariablesIfNeeded(ExpressionVariables variables, DelegateExecution execution, Task wfTask, OperationResult result) throws SchemaException, ObjectNotFoundException { if (variables != null) { return variables; } else { - return getDefaultVariables(execution, result); + return getDefaultVariables(execution, wfTask, result); } } - private ExpressionVariables getDefaultVariables(DelegateExecution execution, OperationResult result) throws SchemaException, ObjectNotFoundException { + private ExpressionVariables getDefaultVariables(DelegateExecution execution, Task wfTask, OperationResult result) throws SchemaException, ObjectNotFoundException { - RepositoryService repositoryService = SpringApplicationContextHolder.getCacheRepositoryService(); - MiscDataUtil miscDataUtil = SpringApplicationContextHolder.getMiscDataUtil(); + RepositoryService repositoryService = getCacheRepositoryService(); + MiscDataUtil miscDataUtil = getMiscDataUtil(); ExpressionVariables variables = new ExpressionVariables(); - try { - variables.addVariableDefinition(SchemaConstants.C_REQUESTER, miscDataUtil.getRequester(execution.getVariables(), result)); - } catch (SchemaException e) { - throw new SchemaException("Couldn't get requester object due to schema exception", e); // todo do we really want to skip the whole processing? perhaps yes, otherwise we could get NPEs - } catch (ObjectNotFoundException e) { - throw new ObjectNotFoundException("Couldn't get requester object due to object not found exception", e); - } + ObjectReferenceType requesterRef = wfTask.getWorkflowContext().getRequesterRef(); + variables.addVariableDefinition(C_REQUESTER, miscDataUtil.resolveObjectReference(requesterRef, result)); - PrismObject objectToBeAdded = (PrismObject) execution.getVariable(PcpProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_TO_BE_ADDED); - if (objectToBeAdded != null) { - variables.addVariableDefinition(SchemaConstants.C_OBJECT, objectToBeAdded); - } else { - String objectOid = (String) execution.getVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID); - if (objectOid != null) { - try { - variables.addVariableDefinition(SchemaConstants.C_OBJECT, repositoryService.getObject(ObjectType.class, objectOid, null, result)); - } catch (SchemaException e) { - throw new SchemaException("Couldn't get requester object due to schema exception", e); // todo do we really want to skip the whole processing? perhaps yes, otherwise we could get NPEs - } catch (ObjectNotFoundException e) { - throw new ObjectNotFoundException("Couldn't get requester object due to object not found exception", e); - } - } - } + ObjectReferenceType objectRef = wfTask.getWorkflowContext().getObjectRef(); + variables.addVariableDefinition(C_OBJECT, miscDataUtil.resolveObjectReference(objectRef, result)); + + ObjectReferenceType targetRef = wfTask.getWorkflowContext().getTargetRef(); // might be null + variables.addVariableDefinition(C_TARGET, miscDataUtil.resolveObjectReference(targetRef, result)); - ObjectDelta objectDelta = null; + ObjectDelta objectDelta = null; try { - objectDelta = miscDataUtil.getFocusPrimaryDelta(execution.getVariables(), true); + objectDelta = miscDataUtil.getFocusPrimaryDelta(wfTask.getWorkflowContext(), true); } catch (JAXBException e) { throw new SchemaException("Couldn't get object delta: " + e.getMessage(), e); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/InitializeLoopThroughLevels.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/InitializeLoopThroughLevels.java index 53db644607f..236305c13ca 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/InitializeLoopThroughLevels.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/InitializeLoopThroughLevels.java @@ -28,13 +28,7 @@ public class InitializeLoopThroughLevels implements JavaDelegate { private static final Trace LOGGER = TraceManager.getTrace(InitializeLoopThroughLevels.class); public void execute(DelegateExecution execution) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Executing the delegate; execution = " + execution); - } - -// ApprovalRequest itemToApprove = (ApprovalRequest) execution.getVariable(ProcessVariableNames.APPROVAL_REQUEST); -// Validate.notNull(itemToApprove, "itemToApprove is null"); - + LOGGER.trace("Executing the delegate; execution = {}", execution); execution.setVariableLocal(ProcessVariableNames.LOOP_LEVELS_STOP, Boolean.FALSE); execution.setVariableLocal(ProcessVariableNames.ALL_DECISIONS, new ArrayList()); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ItemApprovalProcessInterface.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ItemApprovalProcessInterface.java index 94eade14b36..d1b833d7cff 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ItemApprovalProcessInterface.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ItemApprovalProcessInterface.java @@ -16,21 +16,18 @@ package com.evolveum.midpoint.wf.impl.processes.itemApproval; -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismContainerDefinition; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; -import com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; import com.evolveum.midpoint.wf.impl.processes.BaseProcessMidPointInterface; +import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; import com.evolveum.midpoint.wf.util.ApprovalUtils; import com.evolveum.midpoint.xml.ns._public.common.common_3.ApprovalSchemaType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.DecisionType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ItemApprovalProcessStateType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ItemApprovalProcessState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ItemApprovalRequestType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -49,32 +46,25 @@ public class ItemApprovalProcessInterface extends BaseProcessMidPointInterface { @Autowired private PrismContext prismContext; - public void prepareStartInstruction(JobCreationInstruction instruction, ApprovalRequest approvalRequest, String approvalTaskName) { - instruction.setProcessDefinitionKey(PROCESS_DEFINITION_KEY); + public void prepareStartInstruction(WfTaskCreationInstruction instruction) { + instruction.setProcessName(PROCESS_DEFINITION_KEY); instruction.setSimple(false); instruction.setSendStartConfirmation(true); - instruction.addProcessVariable(ProcessVariableNames.APPROVAL_REQUEST, approvalRequest); - instruction.addProcessVariable(ProcessVariableNames.APPROVAL_TASK_NAME, approvalTaskName); instruction.setProcessInterfaceBean(this); } @Override - public ProcessSpecificState externalizeProcessInstanceState(Map variables) { - PrismContainerDefinition extDefinition = prismContext.getSchemaRegistry().findContainerDefinitionByType(ItemApprovalProcessState.COMPLEX_TYPE); - PrismContainer extStateContainer = extDefinition.instantiate(); - ItemApprovalProcessState extState = extStateContainer.createNewValue().asContainerable(); - - PrismContainer extRequestContainer = extDefinition.findContainerDefinition(ItemApprovalProcessState.F_APPROVAL_REQUEST).instantiate(); - ItemApprovalRequestType extRequestType = (ItemApprovalRequestType) extRequestContainer.createNewValue().asContainerable(); + public ItemApprovalProcessStateType externalizeProcessSpecificState(Map variables) { + ItemApprovalProcessStateType extState = new ItemApprovalProcessStateType(prismContext); + com.evolveum.midpoint.xml.ns._public.common.common_3.ItemApprovalRequestType extRequestType = new com.evolveum.midpoint.xml.ns._public + .common.common_3.ItemApprovalRequestType(prismContext); - ApprovalRequest intApprovalRequest = (ApprovalRequest) variables.get(ProcessVariableNames.APPROVAL_REQUEST); - intApprovalRequest.setPrismContext(prismContext); + ApprovalSchema intApprovalSchema = (ApprovalSchema) variables.get(ProcessVariableNames.APPROVAL_SCHEMA); + intApprovalSchema.setPrismContext(prismContext); - ApprovalSchemaType approvalSchemaType = (ApprovalSchemaType) extRequestContainer.getDefinition().findContainerDefinition(ItemApprovalRequestType.F_APPROVAL_SCHEMA).instantiate().createNewValue().asContainerable(); - intApprovalRequest.getApprovalSchema().toApprovalSchemaType(approvalSchemaType); + ApprovalSchemaType approvalSchemaType = new ApprovalSchemaType(prismContext); + intApprovalSchema.toApprovalSchemaType(approvalSchemaType); extRequestType.setApprovalSchema(approvalSchemaType); - extRequestType.setItemToApprove(intApprovalRequest.getItemToApprove()); - extState.setApprovalRequest(extRequestType); List intDecisions = (List) variables.get(ProcessVariableNames.ALL_DECISIONS); if (intDecisions != null) { @@ -83,17 +73,29 @@ public ProcessSpecificState externalizeProcessInstanceState(Map } } - extState.asPrismContainerValue().setConcreteType(ItemApprovalProcessState.COMPLEX_TYPE); + extState.asPrismContainerValue().setConcreteType(ItemApprovalProcessStateType.COMPLEX_TYPE); return extState; } + @Override public DecisionType extractDecision(Map variables) { + DecisionType decision = new DecisionType(); + + decision.setResultAsString((String) variables.get(CommonProcessVariableNames.FORM_FIELD_DECISION)); + decision.setApproved(ApprovalUtils.approvalBooleanValue(decision.getResultAsString())); + decision.setComment((String) variables.get(CommonProcessVariableNames.FORM_FIELD_COMMENT)); + + // TODO - what with other fields (approver, dateTime)? + + return decision; + } + @Override public List prepareApprovedBy(ProcessEvent event) { List retval = new ArrayList(); - if (!ApprovalUtils.isApproved(event.getAnswer())) { + if (!ApprovalUtils.isApproved(getAnswer(event.getVariables()))) { return retval; } - List allDecisions = (List) event.getVariable(ProcessVariableNames.ALL_DECISIONS); + List allDecisions = event.getVariable(ProcessVariableNames.ALL_DECISIONS, List.class); for (Decision decision : allDecisions) { if (decision.isApproved()) { retval.add(MiscSchemaUtil.createObjectReference(decision.getApproverOid(), SchemaConstants.C_USER_TYPE)); diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ItemApprovalSpecificContent.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ItemApprovalSpecificContent.java new file mode 100644 index 00000000000..158be231b83 --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ItemApprovalSpecificContent.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.processes.itemApproval; + +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.wf.impl.tasks.ProcessSpecificContent; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ItemApprovalProcessStateType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessSpecificStateType; + +import java.util.Map; + +/** + * @author mederly + */ +public class ItemApprovalSpecificContent implements ProcessSpecificContent { + + private String taskName; + private ApprovalSchema approvalSchema; + + public void setTaskName(String taskName) { + this.taskName = taskName; + } + + public String getTaskName() { + return taskName; + } + + @Override public void createProcessVariables(Map map, PrismContext prismContext) { + map.put(ProcessVariableNames.APPROVAL_TASK_NAME, taskName); + if (approvalSchema != null) { + map.put(ProcessVariableNames.APPROVAL_SCHEMA, approvalSchema); + } + } + + public void setApprovalSchema(ApprovalSchema approvalSchema) { + this.approvalSchema = approvalSchema; + } + + public ApprovalSchema getApprovalSchema() { + return approvalSchema; + } + + @Override + public WfProcessSpecificStateType createProcessSpecificState() { + ItemApprovalProcessStateType state = new ItemApprovalProcessStateType(); + state.asPrismContainerValue().setConcreteType(ItemApprovalProcessStateType.COMPLEX_TYPE); + state.setApprovalSchema(approvalSchema != null ? approvalSchema.toApprovalSchemaType() : null); + return state; + } +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/PrepareResult.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/PrepareResult.java index 56c225db7c1..1697725d90c 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/PrepareResult.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/PrepareResult.java @@ -19,13 +19,13 @@ import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.impl.processes.BaseProcessMidPointInterface; -import com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder; import com.evolveum.midpoint.wf.util.ApprovalUtils; - import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.JavaDelegate; import org.apache.commons.lang.Validate; +import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.getActivitiInterface; + public class PrepareResult implements JavaDelegate { private static final Trace LOGGER = TraceManager.getTrace(PrepareResult.class); @@ -39,7 +39,7 @@ public void execute(DelegateExecution execution) { execution.setVariable(BaseProcessMidPointInterface.VARIABLE_WF_ANSWER, ApprovalUtils.approvalStringValue(approved)); execution.setVariable(BaseProcessMidPointInterface.VARIABLE_WF_STATE, "Final decision is " + (approved ? "APPROVED" : "REFUSED")); - SpringApplicationContextHolder.getActivitiInterface().notifyMidpointAboutProcessFinishedEvent(execution); + getActivitiInterface().notifyMidpointAboutProcessFinishedEvent(execution); } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ProcessVariableNames.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ProcessVariableNames.java index 20ae03f54ce..25479782149 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ProcessVariableNames.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/ProcessVariableNames.java @@ -21,8 +21,8 @@ */ public class ProcessVariableNames { - // A data structure that describes the request to approve something. Contains item that has to be approved (e.g. assignment) and approval schema. - public static final String APPROVAL_REQUEST = "approvalRequest"; // of type ApprovalRequest + // A data structure that describes the approval schema. + public static final String APPROVAL_SCHEMA = "approvalSchema"; // of type ApprovalSchema // How the user task (work item) should be named. public static final String APPROVAL_TASK_NAME = "approvalTaskName"; // of type String diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/RecordIndividualDecision.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/RecordIndividualDecision.java index a060d00280d..cadc8d4f848 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/RecordIndividualDecision.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/itemApproval/RecordIndividualDecision.java @@ -25,10 +25,8 @@ import com.evolveum.midpoint.wf.impl.processes.BaseProcessMidPointInterface; import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; import com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder; -import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; import com.evolveum.midpoint.wf.util.ApprovalUtils; import com.evolveum.midpoint.xml.ns._public.common.common_3.LevelEvaluationStrategyType; - import org.activiti.engine.delegate.DelegateExecution; import org.activiti.engine.delegate.JavaDelegate; import org.apache.commons.lang.Validate; @@ -36,6 +34,8 @@ import java.util.Date; import java.util.List; +import static com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder.getActivitiInterface; + /** * @author mederly */ @@ -45,10 +45,6 @@ public class RecordIndividualDecision implements JavaDelegate { public void execute(DelegateExecution execution) { - ApprovalRequest approvalRequest = (ApprovalRequest) execution.getVariable(ProcessVariableNames.APPROVAL_REQUEST); - Validate.notNull(approvalRequest, "approvalRequest is null"); - approvalRequest.setPrismContext(SpringApplicationContextHolder.getPrismContext()); - List decisionList = (List) execution.getVariable(ProcessVariableNames.DECISIONS_IN_LEVEL); Validate.notNull(decisionList, "decisionList is null"); @@ -103,7 +99,7 @@ public void execute(DelegateExecution execution) { } if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Logged decision '" + approved + "' for " + approvalRequest); + LOGGER.trace("Logged decision '" + approved + "'"); LOGGER.trace("Resulting decision list = " + decisionList); LOGGER.trace("All decisions = " + allDecisions); } @@ -115,7 +111,7 @@ public void execute(DelegateExecution execution) { } execution.setVariable(BaseProcessMidPointInterface.VARIABLE_WF_STATE, "User " + decision.getApproverName() + " decided to " + (decision.isApproved() ? "approve" : "refuse") + " the request."); - SpringApplicationContextHolder.getActivitiInterface().notifyMidpointAboutProcessEvent(execution); + getActivitiInterface().notifyMidpointAboutProcessEvent(execution); } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseAuditHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseAuditHelper.java index 19d9cd1666e..7e8c3a9efac 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseAuditHelper.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseAuditHelper.java @@ -19,42 +19,34 @@ import com.evolveum.midpoint.audit.api.AuditEventRecord; import com.evolveum.midpoint.audit.api.AuditEventStage; import com.evolveum.midpoint.audit.api.AuditEventType; -import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.repo.api.RepositoryService; -import com.evolveum.midpoint.schema.ObjectDeltaOperation; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.SecurityEnforcer; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.exception.SecurityViolationException; -import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.api.WorkflowException; import com.evolveum.midpoint.wf.impl.activiti.dao.WorkItemProvider; -import com.evolveum.midpoint.wf.impl.jobs.Job; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; import com.evolveum.midpoint.wf.impl.messages.TaskEvent; -import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.wf.impl.processors.primary.PrimaryChangeProcessor; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.DecisionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.GenericObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; -import javax.xml.bind.JAXBException; - -import java.util.List; import java.util.Map; +import static com.evolveum.midpoint.audit.api.AuditEventType.WORKFLOW_PROCESS_INSTANCE; + /** * @author mederly */ @@ -76,26 +68,16 @@ public class BaseAuditHelper { @Qualifier("cacheRepositoryService") private RepositoryService repositoryService; - public AuditEventRecord prepareProcessInstanceAuditRecord(Map variables, Job job, AuditEventStage stage, OperationResult result) { + public AuditEventRecord prepareProcessInstanceAuditRecord(WfTask wfTask, AuditEventStage stage, Map variables, OperationResult result) { AuditEventRecord auditEventRecord = new AuditEventRecord(); - auditEventRecord.setEventType(AuditEventType.WORKFLOW_PROCESS_INSTANCE); + auditEventRecord.setEventType(WORKFLOW_PROCESS_INSTANCE); auditEventRecord.setEventStage(stage); - - String requesterOid = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_REQUESTER_OID); - if (requesterOid != null) { - try { - auditEventRecord.setInitiator(miscDataUtil.getRequester(variables, result)); - } catch (SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve the workflow process instance requester information", e); - } catch (ObjectNotFoundException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve the workflow process instance requester information", e); - } - } + auditEventRecord.setInitiator(wfTask.getRequesterIfExists(result)); PrismObject processInstanceObject = new PrismObject<>(GenericObjectType.COMPLEX_TYPE, GenericObjectType.class); - processInstanceObject.asObjectable().setName(new PolyStringType((String) variables.get(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME))); - processInstanceObject.asObjectable().setOid(job.getActivitiId()); + processInstanceObject.asObjectable().setName(new PolyStringType(wfTask.getProcessInstanceName())); + processInstanceObject.asObjectable().setOid(wfTask.getProcessInstanceId()); auditEventRecord.setTarget(processInstanceObject); auditEventRecord.setOutcome(OperationResultStatus.SUCCESS); @@ -103,44 +85,22 @@ public AuditEventRecord prepareProcessInstanceAuditRecord(Map va return auditEventRecord; } - public AuditEventRecord prepareWorkItemAuditRecord(TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException { + // workItem contains taskRef, assignee, candidates resolved (if possible) + public AuditEventRecord prepareWorkItemAuditRecord(WorkItemType workItem, WfTask wfTask, TaskEvent taskEvent, AuditEventStage stage, + OperationResult result) throws WorkflowException { AuditEventRecord auditEventRecord = new AuditEventRecord(); auditEventRecord.setEventType(AuditEventType.WORK_ITEM); auditEventRecord.setEventStage(stage); + auditEventRecord.setInitiator(wfTask.getRequesterIfExists(result)); - Map variables = taskEvent.getVariables(); - String requesterOid = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_REQUESTER_OID); - if (requesterOid != null) { - try { - auditEventRecord.setInitiator(miscDataUtil.getRequester(variables, result)); - } catch (SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve the workflow process instance requester information", e); - } catch (ObjectNotFoundException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve the workflow process instance requester information", e); - } - } - - WorkItemType workItemType = workItemProvider.taskEventToWorkItem(taskEvent, false, false, result); - - // temporary hacking (work items in audit are not supported) PrismObject targetObject = new PrismObject<>(GenericObjectType.COMPLEX_TYPE, GenericObjectType.class); - targetObject.asObjectable().setName(workItemType.getName()); - targetObject.asObjectable().setOid(workItemType.getWorkItemId()); + targetObject.asObjectable().setName(new PolyStringType(workItem.getName())); + targetObject.asObjectable().setOid(workItem.getWorkItemId()); auditEventRecord.setTarget(targetObject); -// auditEventRecord.setTarget(workItemType.asPrismObject()); - String assigneeOid = taskEvent.getAssigneeOid(); if (stage == AuditEventStage.REQUEST) { - if (assigneeOid != null) { - try { - auditEventRecord.setTargetOwner(repositoryService.getObject(UserType.class, assigneeOid, null, result)); - } catch (ObjectNotFoundException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve the work item assignee information", e); - } catch (SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve the work item assignee information", e); - } - } + auditEventRecord.setTargetOwner((PrismObject) ObjectTypeUtil.getPrismObjectFromReference(workItem.getAssigneeRef())); } else { MidPointPrincipal principal; try { @@ -153,8 +113,11 @@ public AuditEventRecord prepareWorkItemAuditRecord(TaskEvent taskEvent, AuditEve auditEventRecord.setOutcome(OperationResultStatus.SUCCESS); if (stage == AuditEventStage.EXECUTION) { - auditEventRecord.setResult((String) variables.get(CommonProcessVariableNames.FORM_FIELD_DECISION)); - auditEventRecord.setMessage((String) variables.get(CommonProcessVariableNames.FORM_FIELD_COMMENT)); + DecisionType decision = workItem.getDecision(); + if (decision != null) { + auditEventRecord.setResult(decision.getResultAsString()); + auditEventRecord.setMessage(decision.getComment()); + } } return auditEventRecord; diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseChangeProcessor.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseChangeProcessor.java index 69a0cced243..6f8c4bccec4 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseChangeProcessor.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseChangeProcessor.java @@ -1,15 +1,9 @@ package com.evolveum.midpoint.wf.impl.processors; import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.impl.WorkflowManagerImpl; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.WorkItemContents; - import org.apache.commons.configuration.Configuration; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; @@ -17,10 +11,6 @@ import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.annotation.Autowired; -import javax.xml.bind.JAXBException; - -import java.util.Map; - /** * Useful base class for creating change processors. Currently this class deals only with keeping the processor * configuration and context; everything else has been moved to helpers in order to make the code relatively clean. diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseExternalizationHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseExternalizationHelper.java deleted file mode 100644 index 4dc4b25070a..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseExternalizationHelper.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2010-2014 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.processors; - -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; -import com.evolveum.midpoint.prism.xml.XmlTypeConverter; -import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; -import com.evolveum.midpoint.wf.impl.processes.ProcessMidPointInterface; -import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Date; -import java.util.Map; - -/** - * Helps with process state externalization. - * - * (Will probably acquire additional duties later.) - * - * @author mederly - */ -@Component -public class BaseExternalizationHelper { - - @Autowired - private PrismContext prismContext; - - @Autowired - private ProcessInterfaceFinder processInterfaceFinder; - - public PrismObject externalizeState(Map variables) { - PrismObjectDefinition extDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByType(ProcessInstanceState.COMPLEX_TYPE); - PrismObject extStateObject = extDefinition.instantiate(); - ProcessInstanceState extState = extStateObject.asObjectable(); - - extState.setProcessInstanceName((String) variables.get(CommonProcessVariableNames.VARIABLE_PROCESS_INSTANCE_NAME)); - extState.setStartTime(XmlTypeConverter.createXMLGregorianCalendar((Date) variables.get(CommonProcessVariableNames.VARIABLE_START_TIME))); - extState.setShadowTaskOid((String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID)); - extState.setChangeProcessor((String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_PROCESSOR)); - extState.setRequesterOid((String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_REQUESTER_OID)); - extState.setObjectOid((String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID)); - - ProcessMidPointInterface processMidPointInterface = processInterfaceFinder.getProcessInterface(variables); - extState.setAnswer(processMidPointInterface.getAnswer(variables)); - extState.setState(processMidPointInterface.getState(variables)); - - return extStateObject; - } -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseModelInvocationProcessingHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseModelInvocationProcessingHelper.java index c778f3666b4..dc66de8a2c1 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseModelInvocationProcessingHelper.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/BaseModelInvocationProcessingHelper.java @@ -20,16 +20,13 @@ import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobController; -import com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction; -import com.evolveum.midpoint.wf.impl.jobs.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskCreationInstruction; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -55,7 +52,7 @@ public class BaseModelInvocationProcessingHelper { private static final Trace LOGGER = TraceManager.getTrace(BaseModelInvocationProcessingHelper.class); @Autowired - protected JobController jobController; + protected WfTaskController wfTaskController; @Autowired private WfTaskUtil wfTaskUtil; @@ -70,27 +67,26 @@ public class BaseModelInvocationProcessingHelper { * @return the job creation instruction * @throws SchemaException */ - public JobCreationInstruction createInstructionForRoot(ChangeProcessor changeProcessor, ModelContext modelContext, Task taskFromModel, ModelContext contextForRoot) throws SchemaException { + public WfTaskCreationInstruction createInstructionForRoot(ChangeProcessor changeProcessor, ModelContext modelContext, Task taskFromModel, ModelContext contextForRoot) throws SchemaException { - JobCreationInstruction instruction; + WfTaskCreationInstruction instruction; if (contextForRoot != null) { - instruction = JobCreationInstruction.createModelOperationRootJob(changeProcessor, contextForRoot); + instruction = WfTaskCreationInstruction.createModelOnly(changeProcessor, contextForRoot); } else { - instruction = JobCreationInstruction.createNoModelOperationRootJob(changeProcessor); + instruction = WfTaskCreationInstruction.createEmpty(changeProcessor); } instruction.setTaskName(determineRootTaskName(modelContext)); instruction.setTaskObject(determineRootTaskObject(modelContext)); instruction.setTaskOwner(taskFromModel.getOwner()); - instruction.setCreateTaskAsWaiting(true); - + instruction.setCreateTaskAsWaiting(); return instruction; } /** * More specific version of the previous method, having contextForRoot equals to modelContext. */ - public JobCreationInstruction createInstructionForRoot(ChangeProcessor changeProcessor, ModelContext modelContext, Task taskFromModel) throws SchemaException { + public WfTaskCreationInstruction createInstructionForRoot(ChangeProcessor changeProcessor, ModelContext modelContext, Task taskFromModel) throws SchemaException { return createInstructionForRoot(changeProcessor, modelContext, taskFromModel, modelContext); } @@ -154,28 +150,34 @@ private PrismObject determineRootTaskObject(ModelContext context) { * @throws SchemaException * @throws ObjectNotFoundException */ - public Job createRootJob(JobCreationInstruction rootInstruction, Task taskFromModel, OperationResult result) throws SchemaException, ObjectNotFoundException { - Job rootJob = jobController.createJob(rootInstruction, determineParentTaskForRoot(taskFromModel), result); - wfTaskUtil.setRootTaskOidImmediate(taskFromModel, rootJob.getTask().getOid(), result); - return rootJob; + public WfTask submitRootTask(WfTaskCreationInstruction rootInstruction, Task taskFromModel, OperationResult result) + throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { + WfTask rootWfTask = wfTaskController.submitWfTask(rootInstruction, determineParentTaskForRoot(taskFromModel), result); + wfTaskUtil.setRootTaskOidImmediate(taskFromModel, rootWfTask.getTask().getOid(), result); + return rootWfTask; } - public void logJobsBeforeStart(Job rootJob, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("============ Situation just before root task starts waiting for subtasks ============"); - LOGGER.trace("Root job = {}; task = {}", rootJob, rootJob.getTask().debugDump()); - if (rootJob.hasModelContext()) { - LOGGER.trace("Context in root task = " + rootJob.retrieveModelContext(result).debugDump()); - } - List children = rootJob.listChildren(result); - for (int i = 0; i < children.size(); i++) { - Job child = children.get(i); - LOGGER.trace("Child job #" + i + " = {}, its task = {}", child, child.getTask().debugDump()); - if (child.hasModelContext()) { - LOGGER.trace("Context in child task = " + child.retrieveModelContext(result).debugDump()); - } + public void logJobsBeforeStart(WfTask rootWfTask, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException { + if (!LOGGER.isTraceEnabled()) { + return; + } + + StringBuilder sb = new StringBuilder(); + + sb.append("===[ Situation just before root task starts waiting for subtasks ]===\n"); + sb.append("Root job = ").append(rootWfTask).append("; task = ").append(rootWfTask.getTask().debugDump()).append("\n"); + if (rootWfTask.hasModelContext()) { + sb.append("Context in root task: \n").append(rootWfTask.retrieveModelContext(result).debugDump(1)).append("\n"); + } + List children = rootWfTask.listChildren(result); + for (int i = 0; i < children.size(); i++) { + WfTask child = children.get(i); + sb.append("Child job #").append(i).append(" = ").append(child).append(", its task:\n").append(child.getTask().debugDump(1)); + if (child.hasModelContext()) { + sb.append("Context in child task:\n").append(child.retrieveModelContext(result).debugDump(2)); } - LOGGER.trace("Now the root task starts waiting for child tasks"); } + LOGGER.trace("\n{}", sb.toString()); + LOGGER.trace("Now the root task starts waiting for child tasks"); } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/ChangeProcessor.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/ChangeProcessor.java index da823135f2c..71356d4c294 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/ChangeProcessor.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/ChangeProcessor.java @@ -21,7 +21,6 @@ import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.api.hooks.HookOperationMode; import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; @@ -29,14 +28,11 @@ import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.wf.api.WorkflowException; import com.evolveum.midpoint.wf.impl.WorkflowManagerImpl; -import com.evolveum.midpoint.wf.impl.jobs.Job; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; import com.evolveum.midpoint.wf.impl.messages.TaskEvent; import com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.WorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; - -import javax.xml.bind.JAXBException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import java.util.Map; @@ -70,8 +66,9 @@ public interface ChangeProcessor { * * @param context Model context of the operation. * @param wfConfigurationType - *@param taskFromModel Task in context of which the operation is carried out. - * @param result Where to put information on operation execution. @return non-null value if it processed the request; + * @param taskFromModel Task in context of which the operation is carried out. + * @param result Where to put information on operation execution. + * @return non-null value if it processed the request; * BACKGROUND = the process was "caught" by the processor, and continues in background, * FOREGROUND = nothing was left on background, the model operation should continue in foreground, * ERROR = something wrong has happened, there's no point in continuing with this operation. @@ -86,61 +83,37 @@ public interface ChangeProcessor { * Handles an event from WfMS that indicates finishing of the workflow process instance. * Usually, at this point we see what was approved (and what was not) and continue with model operation(s). * - * Should leave the task in saved state (if finishing successfully). - * * @param event - * @param task + * @param wfTask * @param result Here should be stored information about whether the finalization was successful or not * @throws SchemaException */ - void onProcessEnd(ProcessEvent event, Job job, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException; - - /** - * Externalizes internal state of the process instance. Typically, uninteresting (auxiliary) data elements - * are thrown away, internal representation suitable for workflow processing is replaced by "clean" prism - * object structure, and untyped Map[String,Object] is replaced by typed prism data. - * - * @param variables internal process state represented by a map - * @return external representation in the form of PrismObject - */ - PrismObject externalizeProcessInstanceState(Map variables) throws JAXBException, SchemaException; - - /** - * Prepares a displayable work item contents. For example, in case of primary change processor, - * it returns a GeneralChangeApprovalWorkItemContents containing original object state - * (objectOld), to-be object state (objectNew), delta, additional object, and a situation-specific - * question form. - * - * @param task activiti task corresponding to the work item for which the contents is to be prepared - * @param processInstanceVariables variables of the process instance of which this task is a part - * @param result here the method stores its result - * @return - * @throws JAXBException - * @throws ObjectNotFoundException - * @throws SchemaException - */ - PrismObject externalizeWorkItemContents(org.activiti.engine.task.Task task, Map processInstanceVariables, OperationResult result) throws JAXBException, ObjectNotFoundException, SchemaException; + void onProcessEnd(ProcessEvent event, WfTask wfTask, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException; /** * Prepares a process instance-related audit record. * - * @param variables - * @param job + * @param wfTask * @param stage + * @param variables * @param result * @return */ - AuditEventRecord prepareProcessInstanceAuditRecord(Map variables, Job job, AuditEventStage stage, OperationResult result); + AuditEventRecord prepareProcessInstanceAuditRecord(WfTask wfTask, AuditEventStage stage, Map variables, OperationResult result); /** * Prepares a work item-related audit record. * - * @param taskEvent - * @param stage - * @param result - * @return + * + * @param workItem + * @param wfTask + * @param taskEvent + * @param stage + * @param result + * @return */ - AuditEventRecord prepareWorkItemAuditRecord(TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException; + // workItem contains taskRef, assignee, candidates resolved (if possible) + AuditEventRecord prepareWorkItemAuditRecord(WorkItemType workItem, WfTask wfTask, TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException; /** * Auxiliary method to access autowired Spring beans from within non-spring java objects. diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GcpExternalizationHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GcpExternalizationHelper.java index a78f3ec290b..ad51a24b6a7 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GcpExternalizationHelper.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GcpExternalizationHelper.java @@ -17,33 +17,12 @@ package com.evolveum.midpoint.wf.impl.processors.general; import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; -import com.evolveum.midpoint.prism.PrismProperty; -import com.evolveum.midpoint.prism.PrismPropertyDefinition; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.DOMUtil; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine; -import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.QuestionFormType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.WorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; - -import org.activiti.engine.form.FormProperty; -import org.activiti.engine.form.TaskFormData; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.xml.bind.JAXBException; -import javax.xml.namespace.QName; - -import java.util.Map; - /** * @author mederly */ @@ -58,38 +37,5 @@ public class GcpExternalizationHelper { @Autowired private ActivitiEngine activitiEngine; - public PrismObject createNewProcessInstanceState() { - return (PrismObject) prismContext.getSchemaRegistry().findObjectDefinitionByType(ProcessInstanceState.COMPLEX_TYPE).instantiate(); - } - - public PrismObject createNewWorkItemContents() { - PrismObjectDefinition wicDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByType(WorkItemContents.COMPLEX_TYPE); - PrismObject wicPrism = wicDefinition.instantiate(); - - PrismObjectDefinition formDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByType(QuestionFormType.COMPLEX_TYPE); - PrismObject formPrism = formDefinition.instantiate(); - - wicPrism.asObjectable().setQuestionForm(formPrism.asObjectable()); - return wicPrism; - } - - public void fillInQuestionForm(PrismObject formPrism, org.activiti.engine.task.Task task, Map processInstanceVariables, OperationResult result) throws JAXBException, ObjectNotFoundException, SchemaException { - TaskFormData data = activitiEngine.getFormService().getTaskFormData(task.getId()); - for (FormProperty formProperty : data.getFormProperties()) { - if (formProperty.isReadable() && !formProperty.getId().startsWith(CommonProcessVariableNames.FORM_BUTTON_PREFIX)) { - LOGGER.trace("- processing property {} having value {}", formProperty.getId(), formProperty.getValue()); - if (formProperty.getValue() != null) { - QName propertyName = new QName(SchemaConstants.NS_WFCF, formProperty.getId()); - PrismPropertyDefinition prismPropertyDefinition = new PrismPropertyDefinition<>(propertyName, DOMUtil.XSD_STRING, prismContext); - PrismProperty prismProperty = prismPropertyDefinition.instantiate(); - prismProperty.addRealValue(formProperty.getValue()); - formPrism.add(prismProperty); - } - } - } - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Resulting prism object instance = " + formPrism.debugDump()); - } - } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GeneralChangeProcessor.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GeneralChangeProcessor.java index 7966faa720f..82a0085d5ad 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GeneralChangeProcessor.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GeneralChangeProcessor.java @@ -6,45 +6,29 @@ import com.evolveum.midpoint.model.api.hooks.HookOperationMode; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine; import com.evolveum.midpoint.wf.api.WorkflowException; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobController; -import com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction; -import com.evolveum.midpoint.wf.impl.jobs.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskCreationInstruction; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; import com.evolveum.midpoint.wf.impl.messages.TaskEvent; -import com.evolveum.midpoint.wf.impl.processors.BaseAuditHelper; -import com.evolveum.midpoint.wf.impl.processors.BaseChangeProcessor; -import com.evolveum.midpoint.wf.impl.processors.BaseConfigurationHelper; -import com.evolveum.midpoint.wf.impl.processors.BaseExternalizationHelper; -import com.evolveum.midpoint.wf.impl.processors.BaseModelInvocationProcessingHelper; +import com.evolveum.midpoint.wf.impl.processors.*; import com.evolveum.midpoint.wf.impl.processors.general.scenarios.DefaultGcpScenarioBean; import com.evolveum.midpoint.wf.impl.processors.general.scenarios.GcpScenarioBean; import com.evolveum.midpoint.wf.impl.util.SerializationSafeContainer; -import com.evolveum.midpoint.xml.ns._public.common.common_3.GeneralChangeProcessorConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.GeneralChangeProcessorScenarioType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.LensContextType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.WorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import javax.xml.bind.JAXBException; import java.util.Map; /** @@ -62,7 +46,7 @@ public class GeneralChangeProcessor extends BaseChangeProcessor { private WfTaskUtil wfTaskUtil; @Autowired - private JobController jobController; + private WfTaskController wfTaskController; @Autowired private ActivitiEngine activitiEngine; @@ -70,9 +54,6 @@ public class GeneralChangeProcessor extends BaseChangeProcessor { @Autowired private BaseModelInvocationProcessingHelper baseModelInvocationProcessingHelper; - @Autowired - private BaseExternalizationHelper baseExternalizationHelper; - @Autowired private BaseConfigurationHelper baseConfigurationHelper; @@ -153,22 +134,22 @@ private HookOperationMode applyScenario(GeneralChangeProcessorScenarioType scena try { // ========== preparing root task =========== - JobCreationInstruction rootInstruction = baseModelInvocationProcessingHelper.createInstructionForRoot(this, context, taskFromModel); - Job rootJob = baseModelInvocationProcessingHelper.createRootJob(rootInstruction, taskFromModel, result); + WfTaskCreationInstruction rootInstruction = baseModelInvocationProcessingHelper.createInstructionForRoot(this, context, taskFromModel); + WfTask rootWfTask = baseModelInvocationProcessingHelper.submitRootTask(rootInstruction, taskFromModel, result); // ========== preparing child task, starting WF process =========== - JobCreationInstruction instruction = scenarioBean.prepareJobCreationInstruction(scenarioType, (LensContext) context, rootJob, taskFromModel, result); - jobController.createJob(instruction, rootJob, result); + WfTaskCreationInstruction instruction = scenarioBean.prepareJobCreationInstruction(scenarioType, (LensContext) context, rootWfTask, taskFromModel, result); + wfTaskController.submitWfTask(instruction, rootWfTask, result); // ========== complete the action =========== - baseModelInvocationProcessingHelper.logJobsBeforeStart(rootJob, result); - rootJob.startWaitingForSubtasks(result); + baseModelInvocationProcessingHelper.logJobsBeforeStart(rootWfTask, result); + rootWfTask.startWaitingForSubtasks(result); return HookOperationMode.BACKGROUND; - } catch (SchemaException|ObjectNotFoundException|CommunicationException|ConfigurationException|RuntimeException e) { + } catch (SchemaException|ObjectNotFoundException|CommunicationException|ConfigurationException|ObjectAlreadyExistsException|RuntimeException e) { LoggingUtils.logException(LOGGER, "Workflow process(es) could not be started", e); result.recordFatalError("Workflow process(es) could not be started: " + e, e); return HookOperationMode.ERROR; @@ -179,9 +160,9 @@ private HookOperationMode applyScenario(GeneralChangeProcessorScenarioType scena //region Finalizing the processing @Override - public void onProcessEnd(ProcessEvent event, Job job, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException { + public void onProcessEnd(ProcessEvent event, WfTask wfTask, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException { - Task task = job.getTask(); + Task task = wfTask.getTask(); // we simply put model context back into parent task // (or if it is null, we set the task to skip model context processing) @@ -189,7 +170,7 @@ public void onProcessEnd(ProcessEvent event, Job job, OperationResult result) th Task rootTask = task.getParentTask(result); - SerializationSafeContainer contextContainer = (SerializationSafeContainer) event.getVariable(GcpProcessVariableNames.VARIABLE_MODEL_CONTEXT); + SerializationSafeContainer contextContainer = event.getVariable(GcpProcessVariableNames.VARIABLE_MODEL_CONTEXT, SerializationSafeContainer.class); LensContextType lensContextType = null; if (contextContainer != null) { contextContainer.setPrismContext(prismContext); @@ -209,28 +190,16 @@ public void onProcessEnd(ProcessEvent event, Job job, OperationResult result) th } //endregion - //region Externalization methods (including auditing) - @Override - public PrismObject externalizeWorkItemContents(org.activiti.engine.task.Task task, Map processInstanceVariables, OperationResult result) throws JAXBException, ObjectNotFoundException, SchemaException { - return getScenarioBean(processInstanceVariables).externalizeWorkItemContents(task, processInstanceVariables, result); - } - - @Override - public PrismObject externalizeProcessInstanceState(Map variables) throws JAXBException, SchemaException { - PrismObject state = baseExternalizationHelper.externalizeState(variables); - ProcessSpecificState processSpecificState = getScenarioBean(variables).externalizeInstanceState(variables); - state.asObjectable().setProcessSpecificState(processSpecificState); - return state; - } - + //region Auditing @Override - public AuditEventRecord prepareProcessInstanceAuditRecord(Map variables, Job job, AuditEventStage stage, OperationResult result) { - return getScenarioBean(variables).prepareProcessInstanceAuditRecord(variables, job, stage, result); + public AuditEventRecord prepareProcessInstanceAuditRecord(WfTask wfTask, AuditEventStage stage, Map variables, OperationResult result) { + return getScenarioBean(variables).prepareProcessInstanceAuditRecord(variables, wfTask, stage, result); } @Override - public AuditEventRecord prepareWorkItemAuditRecord(TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException { - return getScenarioBean(taskEvent.getVariables()).prepareWorkItemAuditRecord(taskEvent, stage, result); + public AuditEventRecord prepareWorkItemAuditRecord(WorkItemType workItem, WfTask wfTask, TaskEvent taskEvent, AuditEventStage stage, + OperationResult result) throws WorkflowException { + return getScenarioBean(taskEvent.getVariables()).prepareWorkItemAuditRecord(workItem, wfTask, taskEvent, stage, result); } //endregion } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GeneralChangeProcessorSpecificContent.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GeneralChangeProcessorSpecificContent.java new file mode 100644 index 00000000000..8cb0baeddee --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/GeneralChangeProcessorSpecificContent.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.processors.general; + +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.wf.impl.tasks.ProcessorSpecificContent; +import com.evolveum.midpoint.wf.impl.util.JaxbValueContainer; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessorSpecificStateType; + +import java.util.Map; + +/** + * @author mederly + */ +public class GeneralChangeProcessorSpecificContent implements ProcessorSpecificContent { + + private String scenarioBeanName; + private LensContext modelContext; + + public GeneralChangeProcessorSpecificContent(LensContext context) { + this.modelContext = context; + } + + public void setScenarioBeanName(String scenarioBeanName) { + this.scenarioBeanName = scenarioBeanName; + } + + @Override public WfProcessorSpecificStateType createProcessorSpecificState() { + return null; + } + + @Override + public void createProcessVariables(Map map, PrismContext prismContext) throws SchemaException { + if (scenarioBeanName != null) { + map.put(GcpProcessVariableNames.VARIABLE_MIDPOINT_SCENARIO_BEAN_NAME, scenarioBeanName); + } + if (modelContext != null) { + map.put(GcpProcessVariableNames.VARIABLE_MODEL_CONTEXT, new JaxbValueContainer<>(modelContext.toLensContextType(), prismContext)); + } + } +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/scenarios/BaseGcpScenarioBean.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/scenarios/BaseGcpScenarioBean.java index f6ea6a7dd1e..5f84fd9c0ea 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/scenarios/BaseGcpScenarioBean.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/scenarios/BaseGcpScenarioBean.java @@ -21,32 +21,22 @@ import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.wf.api.WorkflowException; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.messages.TaskEvent; import com.evolveum.midpoint.wf.impl.processes.DefaultProcessMidPointInterface; import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; -import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; import com.evolveum.midpoint.wf.impl.processors.BaseAuditHelper; import com.evolveum.midpoint.wf.impl.processors.general.GcpExternalizationHelper; -import com.evolveum.midpoint.wf.impl.processors.general.GcpProcessVariableNames; -import com.evolveum.midpoint.wf.impl.util.JaxbValueContainer; +import com.evolveum.midpoint.wf.impl.processors.general.GeneralChangeProcessorSpecificContent; import com.evolveum.midpoint.xml.ns._public.common.common_3.GeneralChangeProcessorScenarioType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.LensContextType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.WorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; - -import org.activiti.engine.task.Task; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.xml.bind.JAXBException; - import java.util.Map; /** @@ -78,46 +68,46 @@ public boolean determineActivation(GeneralChangeProcessorScenarioType scenarioTy return true; } - @Override - public PrismObject externalizeWorkItemContents(Task task, Map processInstanceVariables, OperationResult result) throws JAXBException, ObjectNotFoundException, SchemaException { - PrismObject prism = gcpExternalizationHelper.createNewWorkItemContents(); - gcpExternalizationHelper.fillInQuestionForm(prism.asObjectable().getQuestionForm().asPrismObject(), task, processInstanceVariables, result); - return prism; - } +// @Override +// public PrismObject externalizeWorkItemContents(Task task, Map processInstanceVariables, OperationResult result) throws JAXBException, ObjectNotFoundException, SchemaException { +// PrismObject prism = gcpExternalizationHelper.createNewWorkItemContents(); +// gcpExternalizationHelper.fillInQuestionForm(prism.asObjectable().getQuestionForm().asPrismObject(), task, processInstanceVariables, result); +// return prism; +// } + +// @Override +// public ProcessSpecificState externalizeInstanceState(Map variables) throws SchemaException { +// if (variables.containsKey(CommonProcessVariableNames.VARIABLE_PROCESS_INTERFACE_BEAN_NAME)) { +// return processInterfaceFinder.getProcessInterface(variables).externalizeProcessInstanceState(variables); +// } else { +// return null; +// } +// } @Override - public ProcessSpecificState externalizeInstanceState(Map variables) throws SchemaException { - if (variables.containsKey(CommonProcessVariableNames.VARIABLE_MIDPOINT_PROCESS_INTERFACE_BEAN_NAME)) { - return processInterfaceFinder.getProcessInterface(variables).externalizeProcessInstanceState(variables); - } else { - return null; - } - } - - @Override - public AuditEventRecord prepareProcessInstanceAuditRecord(Map variables, Job job, AuditEventStage stage, OperationResult result) { - return baseAuditHelper.prepareProcessInstanceAuditRecord(variables, job, stage, result); + public AuditEventRecord prepareProcessInstanceAuditRecord(Map variables, WfTask wfTask, AuditEventStage stage, OperationResult result) { + return baseAuditHelper.prepareProcessInstanceAuditRecord(wfTask, stage, variables, result); // TODO what with missing data (delta, result)? We could at least attempt to determine them ... } @Override - public AuditEventRecord prepareWorkItemAuditRecord(TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException { - return baseAuditHelper.prepareWorkItemAuditRecord(taskEvent, stage, result); + public AuditEventRecord prepareWorkItemAuditRecord(WorkItemType workItem, WfTask wfTask, TaskEvent taskEvent, AuditEventStage stage, + OperationResult result) throws WorkflowException { + return baseAuditHelper.prepareWorkItemAuditRecord(workItem, wfTask, taskEvent, stage, result); // TODO fill-in missing delta somehow } @Override - public JobCreationInstruction prepareJobCreationInstruction(GeneralChangeProcessorScenarioType scenarioType, LensContext context, Job rootJob, com.evolveum.midpoint.task.api.Task taskFromModel, OperationResult result) throws SchemaException { - JobCreationInstruction instruction = JobCreationInstruction.createWfProcessChildJob(rootJob); - instruction.setProcessDefinitionKey(scenarioType.getProcessName()); - if (scenarioType.getBeanName() != null) { - instruction.addProcessVariable(GcpProcessVariableNames.VARIABLE_MIDPOINT_SCENARIO_BEAN_NAME, scenarioType.getBeanName()); - } - instruction.setRequesterOidInProcess(taskFromModel.getOwner()); + public WfTaskCreationInstruction prepareJobCreationInstruction(GeneralChangeProcessorScenarioType scenarioType, LensContext context, WfTask rootWfTask, com.evolveum.midpoint.task.api.Task taskFromModel, OperationResult result) throws SchemaException { + + GeneralChangeProcessorSpecificContent processorInstruction = new GeneralChangeProcessorSpecificContent(context); + processorInstruction.setScenarioBeanName(scenarioType.getBeanName()); + + WfTaskCreationInstruction instruction = WfTaskCreationInstruction.createWfOnly(rootWfTask.getChangeProcessor(), processorInstruction, null); + instruction.setProcessName(scenarioType.getProcessName()); + instruction.setRequesterRef(taskFromModel.getOwner()); instruction.setTaskName("Workflow-monitoring task"); instruction.setProcessInterfaceBean(defaultProcessMidPointInterface); - LensContextType lensContextType = context.toLensContextType(); - instruction.addProcessVariable(GcpProcessVariableNames.VARIABLE_MODEL_CONTEXT, new JaxbValueContainer<>(lensContextType, prismContext)); return instruction; } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/scenarios/GcpScenarioBean.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/scenarios/GcpScenarioBean.java index e4c0d7fa88a..4391425d706 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/scenarios/GcpScenarioBean.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/general/scenarios/GcpScenarioBean.java @@ -20,21 +20,15 @@ import com.evolveum.midpoint.audit.api.AuditEventStage; import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.impl.lens.LensContext; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.wf.api.WorkflowException; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.messages.TaskEvent; import com.evolveum.midpoint.xml.ns._public.common.common_3.GeneralChangeProcessorScenarioType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.WorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; - -import javax.xml.bind.JAXBException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; import java.util.Map; @@ -55,13 +49,9 @@ public interface GcpScenarioBean { */ boolean determineActivation(GeneralChangeProcessorScenarioType scenarioType, ModelContext context, Task taskFromModel, OperationResult result); - PrismObject externalizeWorkItemContents(org.activiti.engine.task.Task task, Map processInstanceVariables, OperationResult result) throws JAXBException, ObjectNotFoundException, SchemaException; - - ProcessSpecificState externalizeInstanceState(Map variables) throws SchemaException; - - AuditEventRecord prepareProcessInstanceAuditRecord(Map variables, Job job, AuditEventStage stage, OperationResult result); + AuditEventRecord prepareProcessInstanceAuditRecord(Map variables, WfTask wfTask, AuditEventStage stage, OperationResult result); - AuditEventRecord prepareWorkItemAuditRecord(TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException; + AuditEventRecord prepareWorkItemAuditRecord(WorkItemType workItem, WfTask wfTask, TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException; - JobCreationInstruction prepareJobCreationInstruction(GeneralChangeProcessorScenarioType scenarioType, LensContext context, Job rootJob, Task taskFromModel, OperationResult result) throws SchemaException; + WfTaskCreationInstruction prepareJobCreationInstruction(GeneralChangeProcessorScenarioType scenarioType, LensContext context, WfTask rootWfTask, Task taskFromModel, OperationResult result) throws SchemaException; } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/ObjectTreeDeltas.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/ObjectTreeDeltas.java index 48998a71d8f..5468af0e8a7 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/ObjectTreeDeltas.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/ObjectTreeDeltas.java @@ -148,6 +148,14 @@ public static String toObjectTreeDeltasTypeXml(ObjectTreeDeltas objectTreeDeltas return objectTreeDeltas != null ? objectTreeDeltas.toObjectTreeDeltasTypeXml() : null; } + public static String toObjectTreeDeltasTypeXml(ObjectTreeDeltasType objectTreeDeltasType, PrismContext prismContext) throws SchemaException { + if (objectTreeDeltasType != null) { + return prismContext.serializeAtomicValue(objectTreeDeltasType, SchemaConstantsGenerated.C_OBJECT_TREE_DELTAS, PrismContext.LANG_XML); + } else { + return null; + } + } + public static ObjectTreeDeltasType toObjectTreeDeltasType(ObjectTreeDeltas objectTreeDeltas) throws SchemaException { return objectTreeDeltas != null ? objectTreeDeltas.toObjectTreeDeltasType() : null; } @@ -170,8 +178,8 @@ public static ObjectTreeDeltas fromObjectTreeDeltasType(ObjectTreeDeltasType del return deltas; } - public List getDeltaList() { - List rv = new ArrayList<>(); + public List> getDeltaList() { + List> rv = new ArrayList<>(); if (focusChange != null) { rv.add(focusChange); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpChildJobCreationInstruction.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpChildJobCreationInstruction.java deleted file mode 100644 index 956f847fcb9..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpChildJobCreationInstruction.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (c) 2010-2014 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.processors.primary; - -import com.evolveum.midpoint.model.api.ModelExecuteOptions; -import com.evolveum.midpoint.model.api.context.ModelContext; -import com.evolveum.midpoint.model.impl.lens.LensContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.delta.ObjectDelta; -import com.evolveum.midpoint.util.DebugUtil; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction; -import com.evolveum.midpoint.wf.impl.processes.common.StringHolder; -import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; -import com.evolveum.midpoint.wf.impl.processors.primary.aspect.PrimaryChangeAspect; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; - -/** - * @author mederly - */ -public class PcpChildJobCreationInstruction extends JobCreationInstruction { - - private boolean executeApprovedChangeImmediately; // should the child job execute approved change immediately (i.e. executeModelOperationHandler must be set as well!) - - protected PcpChildJobCreationInstruction(ChangeProcessor changeProcessor) { - super(changeProcessor); - } - - protected PcpChildJobCreationInstruction(Job parentJob) { - super(parentJob); - } - - public static PcpChildJobCreationInstruction createInstruction(ChangeProcessor changeProcessor) { - PcpChildJobCreationInstruction pcpjci = new PcpChildJobCreationInstruction(changeProcessor); - prepareWfProcessChildJobInternal(pcpjci); - return pcpjci; - } - - public static PcpChildJobCreationInstruction createInstruction(Job parentJob) { - PcpChildJobCreationInstruction pcpjci = new PcpChildJobCreationInstruction(parentJob); - prepareWfProcessChildJobInternal(pcpjci); - return pcpjci; - } - - public boolean isExecuteApprovedChangeImmediately() { - return executeApprovedChangeImmediately; - } - - public void setExecuteApprovedChangeImmediately(boolean executeApprovedChangeImmediately) { - this.executeApprovedChangeImmediately = executeApprovedChangeImmediately; - } - - public void prepareCommonAttributes(PrimaryChangeAspect aspect, ModelContext modelContext, String objectOid, PrismObject requester) throws SchemaException { - - setRequesterOidInProcess(requester); - setObjectOidInProcess(objectOid); - - setExecuteApprovedChangeImmediately(ModelExecuteOptions.isExecuteImmediatelyAfterApproval(((LensContext) modelContext).getOptions())); - - addProcessVariable(PcpProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_ASPECT, aspect.getClass().getName()); - addTaskVariable(getChangeProcessor().getWorkflowManager().getWfTaskUtil().getWfPrimaryChangeAspectPropertyDefinition(), aspect.getClass().getName()); - - if (isExecuteApprovedChangeImmediately()) { - // actually, context should be emptied anyway; but to be sure, let's do it here as well - addTaskModelContext(((PrimaryChangeProcessor) getChangeProcessor()).contextCopyWithNoDelta((LensContext) modelContext)); - setExecuteModelOperationHandler(true); - } - } - - @Deprecated - public void setDeltaProcessAndTaskVariables(ObjectDelta delta) { -// try { -// addProcessVariable(PcpProcessVariableNames.VARIABLE_MIDPOINT_DELTA, new StringHolder(DeltaConvertor.toObjectDeltaTypeXml(delta))); -// } catch(JAXBException e) { -// throw new SystemException("Couldn't store primary delta into the process variable due to JAXB exception", e); -// } catch (SchemaException e) { -// throw new SystemException("Couldn't store primary delta into the process variable due to schema exception", e); -// } -// -// try { -// addTaskDeltasVariable(getChangeProcessor().getWorkflowManager().getWfTaskUtil().getWfDeltaToProcessPropertyDefinition(), delta); -// } catch (SchemaException e) { -// throw new SystemException("Couldn't store primary delta into the task variable due to schema exception", e); -// } -// - setObjectTreeDeltasProcessAndTaskVariables(new ObjectTreeDeltas(delta, getChangeProcessor().getPrismContext())); - } - - public void setObjectTreeDeltasProcessAndTaskVariables(ObjectTreeDeltas objectTreeDeltas) { - try { - addProcessVariable(PcpProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_TREE_DELTAS, - new StringHolder(ObjectTreeDeltas.toObjectTreeDeltasTypeXml(objectTreeDeltas))); - } catch (SchemaException e) { - throw new SystemException("Couldn't store primary delta(s) into the process variable due to schema exception", e); - } - - try { - addTaskVariable(getChangeProcessor().getWorkflowManager().getWfTaskUtil().getWfDeltasToProcessPropertyDefinition(), - ObjectTreeDeltas.toObjectTreeDeltasType(objectTreeDeltas)); - } catch (SchemaException e) { - throw new SystemException("Couldn't store primary delta(s) into the task variable due to schema exception", e); - } - } - - @Override - public String debugDump(int indent) { - StringBuilder sb = new StringBuilder(); - - DebugUtil.indentDebugDump(sb, indent); - sb.append("PrimaryChangeProcessor ChildJobCreationInstruction: (execute approved change immediately = ") - .append(executeApprovedChangeImmediately) - .append(")\n"); - sb.append(super.debugDump(indent+1)); - return sb.toString(); - } -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpChildWfTaskCreationInstruction.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpChildWfTaskCreationInstruction.java new file mode 100644 index 00000000000..25039278156 --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpChildWfTaskCreationInstruction.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010-2014 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.processors.primary; + +import com.evolveum.midpoint.model.api.ModelExecuteOptions; +import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequest; +import com.evolveum.midpoint.wf.impl.processes.itemApproval.ItemApprovalSpecificContent; +import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; +import com.evolveum.midpoint.wf.impl.processors.primary.aspect.PrimaryChangeAspect; +import com.evolveum.midpoint.wf.impl.tasks.ProcessSpecificContent; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskCreationInstruction; +import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; + +/** + * @author mederly + */ +public class PcpChildWfTaskCreationInstruction extends WfTaskCreationInstruction { + + private static final Trace LOGGER = TraceManager.getTrace(PcpChildWfTaskCreationInstruction.class); + + protected PcpChildWfTaskCreationInstruction(ChangeProcessor changeProcessor, PI processInstruction) { + super(changeProcessor, new PrimaryChangeProcessorSpecificContent(changeProcessor.getPrismContext()), processInstruction); + } + + // useful shortcut + public static PcpChildWfTaskCreationInstruction createItemApprovalInstruction(ChangeProcessor changeProcessor, String approvalTaskName, + ApprovalRequest approvalRequest) { + ItemApprovalSpecificContent itemApprovalInstruction = new ItemApprovalSpecificContent(); + itemApprovalInstruction.setTaskName(approvalTaskName); + itemApprovalInstruction.setApprovalSchema(approvalRequest.getApprovalSchema()); + return new PcpChildWfTaskCreationInstruction<>(changeProcessor, itemApprovalInstruction); + } + + public boolean isExecuteApprovedChangeImmediately() { + return processorContent.isExecuteApprovedChangeImmediately(); + } + + public void prepareCommonAttributes(PrimaryChangeAspect aspect, ModelContext modelContext, PrismObject requester) throws SchemaException { + + setRequesterRef(requester); + + processorContent.setExecuteApprovedChangeImmediately(ModelExecuteOptions.isExecuteImmediatelyAfterApproval(((LensContext) modelContext).getOptions())); + + processorContent.createProcessorSpecificState().setChangeAspect(aspect.getClass().getName()); + + if (isExecuteApprovedChangeImmediately()) { + // actually, context should be emptied anyway; but to be sure, let's do it here as well + setTaskModelContext(((PrimaryChangeProcessor) getChangeProcessor()).contextCopyWithNoDelta((LensContext) modelContext)); + setExecuteModelOperationHandler(true); + } + } + + @Deprecated + public void setDeltasToProcess(ObjectDelta delta) { + setDeltasToProcesses(new ObjectTreeDeltas<>(delta, getChangeProcessor().getPrismContext())); + } + + public void setDeltasToProcesses(ObjectTreeDeltas objectTreeDeltas) { + try { + processorContent.createProcessorSpecificState().setDeltasToProcess(ObjectTreeDeltas.toObjectTreeDeltasType(objectTreeDeltas)); + } catch (SchemaException e) { + throw new SystemException("Couldn't store primary delta(s) into the task variable due to schema exception", e); + } + } + + @Override + public String debugDump(int indent) { + StringBuilder sb = new StringBuilder(); + + DebugUtil.indentDebugDump(sb, indent); + sb.append("PrimaryChangeProcessor ChildJobCreationInstruction: (execute approved change immediately = ") + .append(isExecuteApprovedChangeImmediately()) + .append(")\n"); + sb.append(super.debugDump(indent+1)); + return sb.toString(); + } +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpExternalizationHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpExternalizationHelper.java deleted file mode 100644 index b8f3a44bfc4..00000000000 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpExternalizationHelper.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2010-2014 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.processors.primary; - -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismContainerDefinition; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.schema.constants.SchemaConstants; -import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.schema.util.MiscSchemaUtil; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.GeneralChangeApprovalWorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.QuestionFormType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.WorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.PrimaryChangeProcessorState; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.xml.bind.JAXBException; - -import java.util.Map; - -/** - * @author mederly - */ -@Component -public class PcpExternalizationHelper { - - @Autowired - private PcpRepoAccessHelper pcpRepoAccessHelper; - - @Autowired - private PrismContext prismContext; - - @Autowired - private PrimaryChangeProcessor primaryChangeProcessor; - - @Autowired - private MiscDataUtil miscDataUtil; - - public PrimaryChangeProcessorState externalizeState(Map variables) throws JAXBException, SchemaException { - PrismContainerDefinition extDefinition = prismContext.getSchemaRegistry().findContainerDefinitionByType(PrimaryChangeProcessorState.COMPLEX_TYPE); - PrismContainer extStateContainer = extDefinition.instantiate(); - PrimaryChangeProcessorState state = extStateContainer.createNewValue().asContainerable(); - - state.setChangeAspect((String) variables.get(PcpProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_ASPECT)); - - String objectXml = (String) variables.get(PcpProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_TO_BE_ADDED); - if (objectXml != null) { - ObjectType objectToBeAdded = (ObjectType) prismContext.parseObject(objectXml, PrismContext.LANG_XML).asObjectable(); - state.setObjectToBeAdded(objectToBeAdded); - } - //state.setFocusDelta(miscDataUtil.getFocusPrimaryObjectDeltaType(variables, true)); - state.asPrismContainerValue().setConcreteType(PrimaryChangeProcessorState.COMPLEX_TYPE); - return state; - } - - public PrismObject externalizeWorkItemContents(org.activiti.engine.task.Task task, Map processInstanceVariables, OperationResult result) throws JAXBException, ObjectNotFoundException, SchemaException { - - PrismObject wicPrism = prismContext.getSchemaRegistry().findObjectDefinitionByCompileTimeClass(GeneralChangeApprovalWorkItemContents.class).instantiate(); - GeneralChangeApprovalWorkItemContents wic = wicPrism.asObjectable(); - - PrismObject objectBefore = pcpRepoAccessHelper.getObjectBefore(processInstanceVariables, prismContext, result); - if (objectBefore != null) { - wic.setObjectOld(objectBefore.asObjectable()); - if (objectBefore.getOid() != null) { - wic.setObjectOldRef(MiscSchemaUtil.createObjectReference(objectBefore.getOid(), SchemaConstants.C_OBJECT_TYPE)); // todo ...or will we determine real object type? - } - } - - wic.setObjectDelta(miscDataUtil.getFocusPrimaryObjectDeltaType(processInstanceVariables, true)); - - PrismObject objectAfter = pcpRepoAccessHelper.getObjectAfter(processInstanceVariables, wic.getObjectDelta(), objectBefore, prismContext, result); - if (objectAfter != null) { - wic.setObjectNew(objectAfter.asObjectable()); - if (objectAfter.getOid() != null) { - wic.setObjectNewRef(MiscSchemaUtil.createObjectReference(objectAfter.getOid(), SchemaConstants.C_OBJECT_TYPE)); // todo ...or will we determine real object type? - } - } - - PrismObject relatedObject = getRelatedObject(task, processInstanceVariables, result); - if (relatedObject != null) { - wic.setRelatedObject(relatedObject.asObjectable()); - if (relatedObject.getOid() != null) { - wic.setRelatedObjectRef(MiscSchemaUtil.createObjectReference(relatedObject.getOid(), SchemaConstants.C_OBJECT_TYPE)); // todo ...or will we determine real object type? - } - } - - wic.setQuestionForm(asObjectable(getQuestionForm(task, processInstanceVariables, result))); - return wicPrism; - } - - private PrismObject getQuestionForm(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - return primaryChangeProcessor.getChangeAspect(variables).prepareQuestionForm(task, variables, result); - } - - private PrismObject getRelatedObject(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - return primaryChangeProcessor.getChangeAspect(variables).prepareRelatedObject(task, variables, result); - } - - private T asObjectable(PrismObject prismObject) { - return prismObject != null ? prismObject.asObjectable() : null; - } - -} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpProcessVariableNames.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpProcessVariableNames.java index d9f5723487e..20980080621 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpProcessVariableNames.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpProcessVariableNames.java @@ -23,14 +23,14 @@ */ public class PcpProcessVariableNames { - // Java class name of the process aspect (the same as wf:primaryChangeAspect task property) [String] - public static final String VARIABLE_MIDPOINT_CHANGE_ASPECT = "midPointChangeAspect"; + // Java class name of the process aspect [String] + public static final String VARIABLE_CHANGE_ASPECT = "changeAspect"; - // Object that is about to be added (for ADD operation). [ObjectType] - public static final String VARIABLE_MIDPOINT_OBJECT_TO_BE_ADDED = "midPointObjectToBeAdded"; +// // Object that is about to be added (for ADD operation). [ObjectType] +// public static final String VARIABLE_MIDPOINT_OBJECT_TO_BE_ADDED = "midPointObjectToBeAdded"; - // XML representation of the deltas to be approved. (Note that technically a process - // can approve more than one focus/projection deltas; if necessary, this variable would have to be changed.) - // [StringHolder] - public static final String VARIABLE_MIDPOINT_OBJECT_TREE_DELTAS = "midPointObjectTreeDeltas"; +// // XML representation of the deltas to be approved. (Note that technically a process +// // can approve more than one focus/projection deltas; if necessary, this variable would have to be changed.) +// // [StringHolder] +// public static final String VARIABLE_MIDPOINT_OBJECT_TREE_DELTAS = "midPointObjectTreeDeltas"; } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpRepoAccessHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpRepoAccessHelper.java index dae6521362d..92afabba7a9 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpRepoAccessHelper.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpRepoAccessHelper.java @@ -67,59 +67,5 @@ public class PcpRepoAccessHelper { @Autowired private MiscDataUtil miscDataUtil; - public PrismObject getObjectBefore(Map variables, PrismContext prismContext, OperationResult result) throws SchemaException, ObjectNotFoundException, JAXBException { - String objectXml = (String) variables.get(PcpProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_TO_BE_ADDED); - PrismObject object; - if (objectXml != null) { - object = prismContext.parseObject(objectXml, PrismContext.LANG_XML); - } else { - String oid = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID); - if (oid == null) { - return null; - } - //Validate.notNull(oid, "Object OID in process variables is null"); - object = repositoryService.getObject(ObjectType.class, oid, null, result); - } - - if (object.asObjectable() instanceof UserType) { - miscDataUtil.resolveAssignmentTargetReferences((PrismObject) object, result); - } - return object; - } - - public PrismObject getObjectAfter(Map variables, ObjectDeltaType deltaType, PrismObject objectBefore, PrismContext prismContext, OperationResult result) throws JAXBException, SchemaException { - - ObjectDelta delta; - if (deltaType != null) { - delta = DeltaConvertor.createObjectDelta(deltaType, prismContext); - } else { - delta = miscDataUtil.getFocusPrimaryDelta(variables, true); - } - - if (delta == null) { - return null; - } - - PrismObject objectAfter; - if (delta.isAdd()) { - if (delta.getObjectToAdd() != null) { - objectAfter = delta.getObjectToAdd().clone(); - } else { - return null; - } - } else if (delta.isModify()) { - objectAfter = objectBefore.clone(); - delta.applyTo(objectAfter); - } else if (delta.isDelete()) { - return null; - } else { - return null; // should not occur - } - - if (objectAfter.asObjectable() instanceof UserType) { // quite a hack - miscDataUtil.resolveAssignmentTargetReferences((PrismObject) objectAfter, result); - } - return objectAfter; - } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpJob.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpWfTask.java similarity index 69% rename from model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpJob.java rename to model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpWfTask.java index 06dfa4e29a6..98a1c583fb6 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpJob.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PcpWfTask.java @@ -1,10 +1,11 @@ package com.evolveum.midpoint.wf.impl.processors.primary; -import com.evolveum.midpoint.prism.Objectable; -import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.PrimaryChangeAspect; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; @@ -15,12 +16,16 @@ * * @author mederly */ -public class PcpJob extends Job { +public class PcpWfTask extends WfTask { - PcpJob(Job original) { + PcpWfTask(WfTask original) { super(original); } + public PcpWfTask(WfTaskController wfTaskController, Task task, String processInstanceId, ChangeProcessor changeProcessor) { + super(wfTaskController, task, processInstanceId, changeProcessor); + } + public PrimaryChangeAspect getChangeAspect() { return getWfTaskUtil().getPrimaryChangeAspect(getTask(), getPcp().getAllChangeAspects()); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessor.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessor.java index b3bb3dbf813..d101260ed6c 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessor.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessor.java @@ -20,58 +20,45 @@ import com.evolveum.midpoint.audit.api.AuditEventStage; import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.api.context.ModelProjectionContext; -import com.evolveum.midpoint.model.api.context.ModelState; import com.evolveum.midpoint.model.api.hooks.HookOperationMode; import com.evolveum.midpoint.model.impl.lens.LensContext; import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; -import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.ObjectDeltaOperation; import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; -import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.api.WorkflowException; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobController; -import com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction; -import com.evolveum.midpoint.wf.impl.jobs.WfTaskUtil; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; import com.evolveum.midpoint.wf.impl.messages.TaskEvent; import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; import com.evolveum.midpoint.wf.impl.processors.BaseAuditHelper; import com.evolveum.midpoint.wf.impl.processors.BaseChangeProcessor; import com.evolveum.midpoint.wf.impl.processors.BaseConfigurationHelper; -import com.evolveum.midpoint.wf.impl.processors.BaseExternalizationHelper; import com.evolveum.midpoint.wf.impl.processors.BaseModelInvocationProcessingHelper; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.PrimaryChangeAspect; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskCreationInstruction; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PrimaryChangeProcessorConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.WorkItemContents; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessInstanceState; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import javax.xml.bind.JAXBException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; + +import static com.evolveum.midpoint.audit.api.AuditEventStage.EXECUTION; +import static com.evolveum.midpoint.audit.api.AuditEventStage.REQUEST; +import static com.evolveum.midpoint.model.api.context.ModelState.PRIMARY; +import static com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas.extractFromModelContext; +import static com.evolveum.midpoint.wf.impl.processors.primary.PrimaryChangeProcessor.ExecutionMode.*; /** * @author mederly @@ -90,20 +77,14 @@ public class PrimaryChangeProcessor extends BaseChangeProcessor { @Autowired private BaseModelInvocationProcessingHelper baseModelInvocationProcessingHelper; - @Autowired - private BaseExternalizationHelper baseExternalizationHelper; - @Autowired private BaseAuditHelper baseAuditHelper; - @Autowired - private PcpExternalizationHelper pcpExternalizationHelper; - @Autowired private WfTaskUtil wfTaskUtil; @Autowired - private JobController jobController; + private WfTaskController wfTaskController; @Autowired private PcpRepoAccessHelper pcpRepoAccessHelper; @@ -134,13 +115,22 @@ public void init() { // =================================================================================== Processing model invocation @Override - public HookOperationMode processModelInvocation(ModelContext context, WfConfigurationType wfConfigurationType, Task taskFromModel, OperationResult result) throws SchemaException, ObjectNotFoundException { + public HookOperationMode processModelInvocation(ModelContext context, WfConfigurationType wfConfigurationType, Task taskFromModel, OperationResult result) + throws SchemaException, ObjectNotFoundException { - if (context.getState() != ModelState.PRIMARY || context.getFocusContext() == null) { + if (context.getState() != PRIMARY || context.getFocusContext() == null) { return null; } - ObjectTreeDeltas objectTreeDeltas = ObjectTreeDeltas.extractFromModelContext(context); + PrimaryChangeProcessorConfigurationType processorConfigurationType = + wfConfigurationType != null ? wfConfigurationType.getPrimaryChangeProcessor() : null; + + if (processorConfigurationType != null && Boolean.FALSE.equals(processorConfigurationType.isEnabled())) { + LOGGER.debug("Primary change processor is disabled."); + return null; + } + + ObjectTreeDeltas objectTreeDeltas = extractFromModelContext(context); if (objectTreeDeltas.isEmpty()) { return null; } @@ -148,72 +138,37 @@ public HookOperationMode processModelInvocation(ModelContext context, WfConfigur // examine the request using process aspects ObjectTreeDeltas changesBeingDecomposed = objectTreeDeltas.clone(); - List jobCreationInstructions = gatherStartInstructions(context, wfConfigurationType, changesBeingDecomposed, taskFromModel, result); + List childTaskInstructions = gatherStartInstructions( + context, processorConfigurationType, changesBeingDecomposed, taskFromModel, result); // start the process(es) - if (jobCreationInstructions.isEmpty()) { + if (childTaskInstructions.isEmpty()) { LOGGER.trace("There are no workflow processes to be started, exiting."); return null; - } else { - return startJobs(jobCreationInstructions, context, changesBeingDecomposed, taskFromModel, result); } + return submitTasks(childTaskInstructions, context, changesBeingDecomposed, taskFromModel, result); } - private List gatherStartInstructions(ModelContext context, - WfConfigurationType wfConfigurationType, - ObjectTreeDeltas changesBeingDecomposed, - Task taskFromModel, OperationResult result) throws SchemaException, ObjectNotFoundException { - List startProcessInstructions = new ArrayList<>(); - - PrimaryChangeProcessorConfigurationType processorConfigurationType = - wfConfigurationType != null ? wfConfigurationType.getPrimaryChangeProcessor() : null; - - if (processorConfigurationType != null && Boolean.FALSE.equals(processorConfigurationType.isEnabled())) { - LOGGER.debug("Primary change processor is disabled."); - return startProcessInstructions; - } + private List gatherStartInstructions(ModelContext context, + PrimaryChangeProcessorConfigurationType processorConfigurationType, ObjectTreeDeltas changesBeingDecomposed, Task taskFromModel, + OperationResult result) throws SchemaException, ObjectNotFoundException { + List startProcessInstructions = new ArrayList<>(); for (PrimaryChangeAspect aspect : getActiveChangeAspects(processorConfigurationType)) { if (changesBeingDecomposed.isEmpty()) { // nothing left break; } - List instructions = aspect.prepareJobCreationInstructions( - context, wfConfigurationType, changesBeingDecomposed, taskFromModel, result); + List instructions = aspect.prepareTasks(context, processorConfigurationType, changesBeingDecomposed, taskFromModel, result); logAspectResult(aspect, instructions, changesBeingDecomposed); if (instructions != null) { startProcessInstructions.addAll(instructions); } } - - // tweaking the instructions returned from aspects a bit... - - // if we are adding a new object, we have to set OBJECT_TO_BE_ADDED variable in all instructions - ObjectDelta focusChange = changesBeingDecomposed.getFocusChange(); - if (focusChange != null && focusChange.isAdd() && focusChange.getObjectToAdd() != null) { - String objectToBeAdded; - try { - objectToBeAdded = MiscDataUtil.serializeObjectToXml(focusChange.getObjectToAdd()); - } catch (SystemException e) { - throw new SystemException("Couldn't serialize object to be added to XML", e); - } - for (PcpChildJobCreationInstruction instruction : startProcessInstructions) { - instruction.addProcessVariable(PcpProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_TO_BE_ADDED, objectToBeAdded); - } - } - - for (PcpChildJobCreationInstruction instruction : startProcessInstructions) { - if (instruction.startsWorkflowProcess() && instruction.isExecuteApprovedChangeImmediately()) { - // if we want to execute approved changes immediately in this instruction, we have to wait for - // task0 (if there is any) and then to update our model context with the results (if there are any) - instruction.addHandlersAfterWfProcessAtEnd(WfTaskUtil.WAIT_FOR_TASKS_HANDLER_URI, WfPrepareChildOperationTaskHandler.HANDLER_URI); - } - } - return startProcessInstructions; } - private Collection getActiveChangeAspects(PrimaryChangeProcessorConfigurationType processorConfigurationType) { + private Collection getActiveChangeAspects(PrimaryChangeProcessorConfigurationType processorConfigurationType) { Collection rv = new HashSet<>(); for (PrimaryChangeAspect aspect : getAllChangeAspects()) { if (aspect.isEnabled(processorConfigurationType)) { @@ -223,11 +178,11 @@ private Collection getActiveChangeAspects(PrimaryChangeProc return rv; } - private void logAspectResult(PrimaryChangeAspect aspect, List instructions, ObjectTreeDeltas changesBeingDecomposed) { + private void logAspectResult(PrimaryChangeAspect aspect, List instructions, ObjectTreeDeltas changesBeingDecomposed) { if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Aspect " + aspect.getClass() + " returned the following process start instructions (count: " + (instructions == null ? "(null)" : instructions.size()) + "):"); + LOGGER.trace("\n---[ Aspect {} returned the following process start instructions (count: {}) ]---", aspect.getClass(), instructions == null ? "(null)" : instructions.size()); if (instructions != null) { - for (JobCreationInstruction instruction : instructions) { + for (WfTaskCreationInstruction instruction : instructions) { LOGGER.trace(instruction.debugDump(0)); } LOGGER.trace("Remaining delta(s):\n{}", changesBeingDecomposed.debugDump()); @@ -235,37 +190,39 @@ private void logAspectResult(PrimaryChangeAspect aspect, List instructions, final ModelContext context, final ObjectTreeDeltas changesWithoutApproval, Task taskFromModel, OperationResult result) { + private HookOperationMode submitTasks(List instructions, final ModelContext context, final ObjectTreeDeltas changesWithoutApproval, Task taskFromModel, OperationResult result) { try { - // prepare root job and job0 - ExecutionMode executionMode = determineExecutionMode(instructions); - Job rootJob = createRootJob(context, changesWithoutApproval, taskFromModel, result, executionMode); - Job job0 = createJob0(context, changesWithoutApproval, rootJob, executionMode, result); + ExecutionMode executionMode = determineExecutionMode(instructions); + + // prepare root task and task0 + WfTask rootWfTask = submitRootTask(context, changesWithoutApproval, taskFromModel, executionMode, result); + WfTask wfTask0 = submitTask0(context, changesWithoutApproval, rootWfTask, executionMode, result); // start the jobs - List jobs = new ArrayList<>(instructions.size()); - for (JobCreationInstruction instruction : instructions) { - Job job = jobController.createJob(instruction, rootJob.getTask(), result); - jobs.add(job); + List wfTasks = new ArrayList<>(instructions.size()); + for (PcpChildWfTaskCreationInstruction instruction : instructions) { + if (instruction.startsWorkflowProcess() && instruction.isExecuteApprovedChangeImmediately()) { + // if we want to execute approved changes immediately in this instruction, we have to wait for + // task0 (if there is any) and then to update our model context with the results (if there are any) + // TODO CONSIDER THIS... when OID is no longer transferred + instruction.addHandlersAfterWfProcessAtEnd(WfTaskUtil.WAIT_FOR_TASKS_HANDLER_URI, WfPrepareChildOperationTaskHandler.HANDLER_URI); + } + WfTask wfTask = wfTaskController.submitWfTask(instruction, rootWfTask.getTask(), result); + wfTasks.add(wfTask); } // all jobs depend on job0 (if there is one) - if (job0 != null) { - for (Job job : jobs) { - job0.addDependent(job); + if (wfTask0 != null) { + for (WfTask wfTask : wfTasks) { + wfTask0.addDependent(wfTask); } - job0.commitChanges(result); + wfTask0.commitChanges(result); } - // now start the tasks - and exit - - baseModelInvocationProcessingHelper.logJobsBeforeStart(rootJob, result); - if (job0 != null) { - job0.resumeTask(result); - } - rootJob.startWaitingForSubtasks(result); + baseModelInvocationProcessingHelper.logJobsBeforeStart(rootWfTask, result); + rootWfTask.startWaitingForSubtasks(result); return HookOperationMode.BACKGROUND; } catch (SchemaException|ObjectNotFoundException|ObjectAlreadyExistsException|CommunicationException|ConfigurationException|RuntimeException e) { @@ -277,38 +234,34 @@ private HookOperationMode startJobs(List instruc } } - private Job createRootJob(ModelContext context, ObjectTreeDeltas changesWithoutApproval, Task taskFromModel, OperationResult result, ExecutionMode executionMode) throws SchemaException, ObjectNotFoundException { - LensContext contextForRootTask = determineContextForRootTask(context, changesWithoutApproval, executionMode); - JobCreationInstruction instructionForRoot = baseModelInvocationProcessingHelper.createInstructionForRoot(this, context, taskFromModel, contextForRootTask); - if (executionMode != ExecutionMode.ALL_IMMEDIATELY) { - instructionForRoot.setHandlersBeforeModelOperation(WfPrepareRootOperationTaskHandler.HANDLER_URI); // gather all deltas from child objects - instructionForRoot.setExecuteModelOperationHandler(true); - } - return baseModelInvocationProcessingHelper.createRootJob(instructionForRoot, taskFromModel, result); + private WfTask submitRootTask(ModelContext context, ObjectTreeDeltas changesWithoutApproval, Task taskFromModel, ExecutionMode executionMode, + OperationResult result) + throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { + LensContext lensContextForRootTask = determineLensContextForRootTask(context, changesWithoutApproval, executionMode); + WfTaskCreationInstruction instructionForRoot = baseModelInvocationProcessingHelper.createInstructionForRoot(this, context, taskFromModel, lensContextForRootTask); + if (executionMode != ALL_IMMEDIATELY) { + instructionForRoot.setHandlersBeforeModelOperation(WfPrepareRootOperationTaskHandler.HANDLER_URI); // gather all deltas from child objects + } + return baseModelInvocationProcessingHelper.submitRootTask(instructionForRoot, taskFromModel, result); } - // Child job0 - in modes 2, 3 we have to prepare first child that executes all changes that do not require approval - private Job createJob0(ModelContext context, ObjectTreeDeltas changesWithoutApproval, Job rootJob, ExecutionMode executionMode, OperationResult result) throws SchemaException, ObjectNotFoundException { - if (changesWithoutApproval != null && !changesWithoutApproval.isEmpty() && executionMode != ExecutionMode.ALL_AFTERWARDS) { - ModelContext modelContext = contextCopyWithDeltaReplaced(context, changesWithoutApproval); - JobCreationInstruction instruction0 = JobCreationInstruction.createModelOperationChildJob(rootJob, modelContext); + // Child task0 - in modes 2, 3 we have to prepare first child that executes all changes that do not require approval + private WfTask submitTask0(ModelContext context, ObjectTreeDeltas changesWithoutApproval, WfTask rootWfTask, ExecutionMode executionMode, OperationResult result) throws SchemaException, ObjectNotFoundException { + if (changesWithoutApproval != null && !changesWithoutApproval.isEmpty() && executionMode != ALL_AFTERWARDS) { + ModelContext task0context = contextCopyWithDeltasReplaced(context, changesWithoutApproval); + WfTaskCreationInstruction instruction0 = WfTaskCreationInstruction.createModelOnly(rootWfTask.getChangeProcessor(), task0context); instruction0.setTaskName("Executing changes that do not require approval"); - if (context.getFocusContext().getPrimaryDelta().isAdd()) { - instruction0.setHandlersAfterModelOperation(WfPropagateTaskObjectReferenceTaskHandler.HANDLER_URI); // for add operations we have to propagate ObjectOID - } - instruction0.setCreateTaskAsSuspended(true); // task0 should execute only after all subtasks are created, because when it finishes, it - // writes some information to all dependent tasks (i.e. they must exist at that time) - return jobController.createJob(instruction0, rootJob, result); + return wfTaskController.submitWfTask(instruction0, rootWfTask, result); } else { return null; } } - private LensContext determineContextForRootTask(ModelContext context, ObjectTreeDeltas changesWithoutApproval, ExecutionMode executionMode) throws SchemaException { + private LensContext determineLensContextForRootTask(ModelContext context, ObjectTreeDeltas changesWithoutApproval, ExecutionMode executionMode) throws SchemaException { LensContext contextForRootTask; - if (executionMode == ExecutionMode.ALL_AFTERWARDS) { - contextForRootTask = contextCopyWithDeltaReplaced(context, changesWithoutApproval); - } else if (executionMode == ExecutionMode.MIXED) { + if (executionMode == ALL_AFTERWARDS) { + contextForRootTask = contextCopyWithDeltasReplaced(context, changesWithoutApproval); + } else if (executionMode == MIXED) { contextForRootTask = contextCopyWithNoDelta(context); } else { contextForRootTask = null; @@ -316,7 +269,7 @@ private LensContext determineContextForRootTask(ModelContext context, ObjectTree return contextForRootTask; } - private LensContext contextCopyWithDeltaReplaced(ModelContext context, ObjectTreeDeltas changes) throws SchemaException { + private LensContext contextCopyWithDeltasReplaced(ModelContext context, ObjectTreeDeltas changes) throws SchemaException { Validate.notNull(changes, "changes"); LensContext contextCopy = ((LensContext) context).clone(); @@ -340,20 +293,20 @@ public LensContext contextCopyWithNoDelta(ModelContext context) { return contextCopy; } - private ExecutionMode determineExecutionMode(List instructions) { + private ExecutionMode determineExecutionMode(List instructions) { ExecutionMode executionMode; if (shouldAllExecuteImmediately(instructions)) { - executionMode = ExecutionMode.ALL_IMMEDIATELY; + executionMode = ALL_IMMEDIATELY; } else if (shouldAllExecuteAfterwards(instructions)) { - executionMode = ExecutionMode.ALL_AFTERWARDS; + executionMode = ALL_AFTERWARDS; } else { - executionMode = ExecutionMode.MIXED; + executionMode = MIXED; } return executionMode; } - private boolean shouldAllExecuteImmediately(List startProcessInstructions) { - for (PcpChildJobCreationInstruction instruction : startProcessInstructions) { + private boolean shouldAllExecuteImmediately(List startProcessInstructions) { + for (PcpChildWfTaskCreationInstruction instruction : startProcessInstructions) { if (!instruction.isExecuteApprovedChangeImmediately()) { return false; } @@ -361,8 +314,8 @@ private boolean shouldAllExecuteImmediately(List return true; } - private boolean shouldAllExecuteAfterwards(List startProcessInstructions) { - for (PcpChildJobCreationInstruction instruction : startProcessInstructions) { + private boolean shouldAllExecuteAfterwards(List startProcessInstructions) { + for (PcpChildWfTaskCreationInstruction instruction : startProcessInstructions) { if (instruction.isExecuteApprovedChangeImmediately()) { return false; } @@ -373,78 +326,63 @@ private boolean shouldAllExecuteAfterwards(List //region Processing process finish event @Override - public void onProcessEnd(ProcessEvent event, Job job, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException { - PcpJob pcpJob = new PcpJob(job); + public void onProcessEnd(ProcessEvent event, WfTask wfTask, OperationResult result) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException { + PcpWfTask pcpJob = new PcpWfTask(wfTask); PrimaryChangeAspect aspect = pcpJob.getChangeAspect(); pcpJob.storeResultingDeltas(aspect.prepareDeltaOut(event, pcpJob, result)); pcpJob.addApprovedBy(aspect.prepareApprovedBy(event, pcpJob, result)); - pcpJob.commitChanges(result); - } - //endregion - - @Override - public PrismObject externalizeProcessInstanceState(Map variables) throws JAXBException, SchemaException { - - PrismObject processInstanceStatePrismObject = baseExternalizationHelper.externalizeState(variables); - processInstanceStatePrismObject.asObjectable().setProcessorSpecificState(pcpExternalizationHelper.externalizeState(variables)); - processInstanceStatePrismObject.asObjectable().setProcessSpecificState(getChangeAspect(variables).externalizeProcessInstanceState(variables)); - return processInstanceStatePrismObject; - } - - @Override - public PrismObject externalizeWorkItemContents(org.activiti.engine.task.Task task, Map processInstanceVariables, OperationResult result) throws JAXBException, ObjectNotFoundException, SchemaException { - return pcpExternalizationHelper.externalizeWorkItemContents(task, processInstanceVariables, result); } //endregion //region Auditing @Override - public AuditEventRecord prepareProcessInstanceAuditRecord(Map variables, Job job, AuditEventStage stage, OperationResult result) { - AuditEventRecord auditEventRecord = baseAuditHelper.prepareProcessInstanceAuditRecord(variables, job, stage, result); + public AuditEventRecord prepareProcessInstanceAuditRecord(WfTask wfTask, AuditEventStage stage, Map variables, OperationResult result) { + AuditEventRecord auditEventRecord = baseAuditHelper.prepareProcessInstanceAuditRecord(wfTask, stage, variables, result); - ObjectTreeDeltas deltas = null; + ObjectTreeDeltas deltas = null; try { - if (stage == AuditEventStage.REQUEST) { - deltas = wfTaskUtil.retrieveDeltasToProcess(job.getTask()); - //LOGGER.info("### deltas to process = {}", deltas); + if (stage == REQUEST) { + deltas = wfTaskUtil.retrieveDeltasToProcess(wfTask.getTask()); } else { - deltas = wfTaskUtil.retrieveResultingDeltas(job.getTask()); - //LOGGER.info("### resulting deltas = {}", deltas); + deltas = wfTaskUtil.retrieveResultingDeltas(wfTask.getTask()); } } catch (SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve delta(s) from task " + job.getTask(), e); + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't retrieve delta(s) from task " + wfTask.getTask(), e); } if (deltas != null) { - List deltaList = deltas.getDeltaList(); + List> deltaList = deltas.getDeltaList(); for (ObjectDelta delta : deltaList) { auditEventRecord.addDelta(new ObjectDeltaOperation(delta)); } } - if (stage == AuditEventStage.EXECUTION) { - auditEventRecord.setResult(processInterfaceFinder.getProcessInterface(variables).getAnswer(variables)); + if (stage == EXECUTION) { + auditEventRecord.setResult(wfTask.getAnswer()); } return auditEventRecord; } @Override - public AuditEventRecord prepareWorkItemAuditRecord(TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException { - AuditEventRecord auditEventRecord = baseAuditHelper.prepareWorkItemAuditRecord(taskEvent, stage, result); - ObjectTreeDeltas deltas = null; + public AuditEventRecord prepareWorkItemAuditRecord(WorkItemType workItem, WfTask wfTask, TaskEvent taskEvent, AuditEventStage stage, + OperationResult result) throws WorkflowException { + AuditEventRecord auditEventRecord = baseAuditHelper.prepareWorkItemAuditRecord(workItem, wfTask, taskEvent, stage, result); + + ObjectTreeDeltas deltas = null; try { - deltas = miscDataUtil.getObjectTreeDeltas(taskEvent.getVariables(), true); - if (deltas != null) { - List deltaList = deltas.getDeltaList(); - for (ObjectDelta delta : deltaList) { - auditEventRecord.addDelta(new ObjectDeltaOperation(delta)); - } - } - } catch (JAXBException|SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't retrieve delta to be approved", e); + deltas = getWfTaskUtil().retrieveDeltasToProcess(wfTask.getTask()); + } catch (SchemaException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't retrieve deltas to be put into audit record", e); } - return auditEventRecord; + + if (deltas != null) { + for (ObjectDelta delta : deltas.getDeltaList()) { + auditEventRecord.addDelta(new ObjectDeltaOperation(delta)); + } + } + + return auditEventRecord; } //endregion @@ -455,7 +393,7 @@ public Collection getAllChangeAspects() { } PrimaryChangeAspect getChangeAspect(Map variables) { - String aspectClassName = (String) variables.get(PcpProcessVariableNames.VARIABLE_MIDPOINT_CHANGE_ASPECT); + String aspectClassName = (String) variables.get(PcpProcessVariableNames.VARIABLE_CHANGE_ASPECT); return findPrimaryChangeAspect(aspectClassName); } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessorSpecificContent.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessorSpecificContent.java new file mode 100644 index 00000000000..686791bc414 --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/PrimaryChangeProcessorSpecificContent.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.processors.primary; + +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.wf.impl.tasks.ProcessorSpecificContent; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfPrimaryChangeProcessorStateType; + +import java.util.Map; + +/** + * @author mederly + */ +public class PrimaryChangeProcessorSpecificContent implements ProcessorSpecificContent { + + private final WfPrimaryChangeProcessorStateType processorState; + private boolean executeApprovedChangeImmediately; // should the child job execute approved change immediately (i.e. executeModelOperationHandler must be set as well!) + + public PrimaryChangeProcessorSpecificContent(PrismContext prismContext) { + processorState = new WfPrimaryChangeProcessorStateType(prismContext); + processorState.asPrismContainerValue().setConcreteType(WfPrimaryChangeProcessorStateType.COMPLEX_TYPE); + } + + public WfPrimaryChangeProcessorStateType createProcessorSpecificState() { + return processorState; + } + + public boolean isExecuteApprovedChangeImmediately() { + return executeApprovedChangeImmediately; + } + + public void setExecuteApprovedChangeImmediately(boolean executeApprovedChangeImmediately) { + this.executeApprovedChangeImmediately = executeApprovedChangeImmediately; + } + + @Override public void createProcessVariables(Map map, PrismContext prismContext) throws SchemaException { + map.put(PcpProcessVariableNames.VARIABLE_CHANGE_ASPECT, processorState.getChangeAspect()); + } +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPrepareChildOperationTaskHandler.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPrepareChildOperationTaskHandler.java index 8fbbdc40937..cb2faa7deb8 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPrepareChildOperationTaskHandler.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPrepareChildOperationTaskHandler.java @@ -21,34 +21,21 @@ */ import com.evolveum.midpoint.model.api.context.ModelContext; -import com.evolveum.midpoint.model.impl.lens.LensContext; -import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.result.OperationResult; -import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.task.api.TaskCategory; -import com.evolveum.midpoint.task.api.TaskHandler; -import com.evolveum.midpoint.task.api.TaskManager; -import com.evolveum.midpoint.task.api.TaskRunResult; -import com.evolveum.midpoint.util.exception.CommunicationException; -import com.evolveum.midpoint.util.exception.ConfigurationException; -import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; -import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.task.api.*; +import com.evolveum.midpoint.util.exception.*; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobController; - +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; -import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; - import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -57,7 +44,6 @@ /** * This handler prepares model operation to be executed within the context of child task: * - prepares model operation context, filling it up with approved delta(s) - * - adds OID if necessary (if delta0 was 'add object' delta) * * @author mederly */ @@ -75,7 +61,7 @@ public class WfPrepareChildOperationTaskHandler implements TaskHandler { private TaskManager taskManager; @Autowired - private JobController jobController; + private WfTaskController wfTaskController; @PostConstruct public void init() { @@ -85,6 +71,7 @@ public void init() { //endregion //region Body + @SuppressWarnings("unchecked") @Override public TaskRunResult run(Task task) { @@ -94,134 +81,57 @@ public TaskRunResult run(Task task) { try { - Job job = jobController.recreateJob(task); + WfTask wfTask = wfTaskController.recreateWfTask(task); OperationResult result = task.getResult(); - ModelContext modelContext = job.retrieveModelContext(result); + ModelContext modelContext = wfTask.retrieveModelContext(result); if (modelContext == null) { throw new IllegalStateException("There's no model context in child task; task = " + task); } // prepare deltaOut to be used - ObjectTreeDeltas deltasOut = job.retrieveResultingDeltas(); + ObjectTreeDeltas deltasOut = wfTask.retrieveResultingDeltas(); if (LOGGER.isTraceEnabled()) { dumpDeltaOut(deltasOut); } if (deltasOut == null || deltasOut.isEmpty()) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("There's no primary delta in focus context; task = " + task + ", model context = " + modelContext.debugDump()); - LOGGER.trace("We'll delete model operation context."); + LOGGER.trace("There's no primary delta in focus context; we'll delete model operation context. Task = {}, model context:\n{}", task, modelContext.debugDump()); } - - job.deleteModelOperationContext(result); - + wfTask.deleteModelOperationContext(); } else { - - // TODO what about projection deltas? - setOidIfNeeded(deltasOut.getFocusChange(), task, result); // fixes OID in deltaOut, if necessary - -// if (deltaOut.getOid() == null || deltaOut.getOid().equals(PrimaryChangeProcessor.UNKNOWN_OID)) { -// throw new IllegalStateException("Null or unknown OID in deltaOut: " + deltaOut.getOid()); -// } - // place deltaOut into model context - -// ObjectDelta existingPrimaryDelta = modelContext.getFocusContext().getPrimaryDelta(); -// if (existingPrimaryDelta == null || !existingPrimaryDelta.isModify()) { -// throw new IllegalStateException("Object delta in model context in task " + task + " should have been empty or of MODIFY type, but it isn't; it is " + existingPrimaryDelta.debugDump()); -// } - modelContext.getFocusContext().setPrimaryDelta(deltasOut.getFocusChange()); Set>> entries = deltasOut.getProjectionChangeMapEntries(); for (Map.Entry> entry : entries) { // TODO what if projection context does not exist? modelContext.findProjectionContext(entry.getKey()).setPrimaryDelta(entry.getValue()); } - if (LOGGER.isTraceEnabled()) { LOGGER.trace("Resulting model context to be stored into task {}:\n{}", task, modelContext.debugDump(0)); } - job.storeModelContext(modelContext); + wfTask.storeModelContext(modelContext); } - task.savePendingModifications(result); - - } catch (SchemaException e) { - LoggingUtils.logException(LOGGER, "Couldn't prepare child model context due to schema exception", e); - status = TaskRunResult.TaskRunResultStatus.PERMANENT_ERROR; - } catch (ObjectNotFoundException e) { - LoggingUtils.logException(LOGGER, "Couldn't prepare child model context", e); - status = TaskRunResult.TaskRunResultStatus.PERMANENT_ERROR; - } catch (ObjectAlreadyExistsException e) { - LoggingUtils.logException(LOGGER, "Couldn't prepare child model context", e); + } catch (SchemaException | ObjectNotFoundException | ObjectAlreadyExistsException | ConfigurationException | RuntimeException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't prepare child model context", e); status = TaskRunResult.TaskRunResultStatus.PERMANENT_ERROR; } catch (CommunicationException e) { LoggingUtils.logException(LOGGER, "Couldn't prepare child model context", e); status = TaskRunResult.TaskRunResultStatus.TEMPORARY_ERROR; - } catch (ConfigurationException e) { - LoggingUtils.logException(LOGGER, "Couldn't prepare child model context", e); - status = TaskRunResult.TaskRunResultStatus.PERMANENT_ERROR; } - TaskRunResult runResult = new TaskRunResult(); runResult.setRunResultStatus(status); return runResult; } - private void setOidIfNeeded(ObjectDelta deltaOut, Task task, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException { - - if (deltaOut == null) { - return; - } - - List prerequisites = task.listPrerequisiteTasks(result); - - if (prerequisites.isEmpty()) { - return; // this should not happen; however, if it happens, it means we have no source of OID available - } - - if (prerequisites.size() > 1) { - throw new IllegalStateException("Child task should have at most one prerequisite (task0); this one has " + prerequisites.size() + "; task = " + task); - } - - Task task0 = prerequisites.get(0); - Job job0 = jobController.recreateJob(task0); - Validate.isTrue(task0.isClosed(), "Task0 should be already closed; it is " + task0.getExecutionStatus()); - - LensContext context0 = (LensContext) job0.retrieveModelContext(result); - if (context0 == null) { - throw new IllegalStateException("There's no model context in task0; task0 = " + task); - } - - String oidInTask0 = context0.getFocusContext().getOid(); - if (oidInTask0 == null) { - throw new IllegalStateException("There's no focus OID in model context in task0; task0 = " + task + "; context = " + context0.debugDump()); - } - - String currentOid = deltaOut.getOid(); - LOGGER.trace("Object OID in task0 = " + oidInTask0 + ", current OID in this task = " + currentOid); - - if (PrimaryChangeProcessor.UNKNOWN_OID.equals(currentOid)) { - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Replaced delta OID with " + oidInTask0 + " in task " + task); - } - deltaOut.setOid(oidInTask0); - } else { - if (!oidInTask0.equals(currentOid)) { - throw new IllegalStateException("Object OID in partial child task (" + currentOid + ") differs from OID in task0 (" + oidInTask0 + ")"); - } - LOGGER.trace("Delta OID is current, we will not change it."); - } - } - // TODO implement correctly - private void dumpDeltaOut(ObjectTreeDeltas deltasOut) { - List> deltaOut = deltasOut != null ? deltasOut.getDeltaList() : new ArrayList<>(); - LOGGER.trace("deltaOut has " + deltaOut.size() + " modifications:"); - for (ObjectDelta delta : deltaOut) { - LOGGER.trace(delta.debugDump()); + private void dumpDeltaOut(ObjectTreeDeltas deltasOut) { + List> deltaOut = deltasOut != null ? deltasOut.getDeltaList() : new ArrayList>(); + LOGGER.trace("deltaOut has {} modifications:", deltaOut.size()); + for (ObjectDelta delta : deltaOut) { + LOGGER.trace("{}", delta.debugDump()); } } //endregion diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPrepareRootOperationTaskHandler.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPrepareRootOperationTaskHandler.java index 0a736c3f92c..f0e3bcfdd0e 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPrepareRootOperationTaskHandler.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPrepareRootOperationTaskHandler.java @@ -28,8 +28,8 @@ import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobController; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType; import org.springframework.beans.factory.annotation.Autowired; @@ -59,7 +59,7 @@ public class WfPrepareRootOperationTaskHandler implements TaskHandler { private TaskManager taskManager; @Autowired - private JobController jobController; + private WfTaskController wfTaskController; @PostConstruct public void init() { @@ -78,13 +78,13 @@ public TaskRunResult run(Task task) { OperationResult result = task.getResult(); - Job rootJob = jobController.recreateRootJob(task); - List children = rootJob.listChildren(result); + WfTask rootWfTask = wfTaskController.recreateRootWfTask(task); + List children = rootWfTask.listChildren(result); - LensContext rootContext = (LensContext) rootJob.retrieveModelContext(result); + LensContext rootContext = (LensContext) rootWfTask.retrieveModelContext(result); boolean changed = false; - for (Job child : children) { + for (WfTask child : children) { if (child.getTaskExecutionStatus() != TaskExecutionStatus.CLOSED) { throw new IllegalStateException("Child task " + child + " is not in CLOSED state; its state is " + child.getTaskExecutionStatus()); @@ -142,8 +142,8 @@ public TaskRunResult run(Task task) { } if (changed) { - rootJob.storeModelContext(rootContext); - rootJob.commitChanges(result); + rootWfTask.storeModelContext(rootContext); + rootWfTask.commitChanges(result); } } catch (SchemaException e) { diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPropagateTaskObjectReferenceTaskHandler.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPropagateTaskObjectReferenceTaskHandler.java index da7d6aa03b6..4eb06ef9b53 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPropagateTaskObjectReferenceTaskHandler.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/WfPropagateTaskObjectReferenceTaskHandler.java @@ -29,9 +29,9 @@ import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.jobs.Job; -import com.evolveum.midpoint.wf.impl.jobs.JobController; -import com.evolveum.midpoint.wf.impl.jobs.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.tasks.WfTask; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskController; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import org.springframework.beans.factory.annotation.Autowired; @@ -62,7 +62,7 @@ public class WfPropagateTaskObjectReferenceTaskHandler implements TaskHandler { private TaskManager taskManager; @Autowired - private JobController jobController; + private WfTaskController wfTaskController; @Autowired private WfTaskUtil wfTaskUtil; @@ -82,36 +82,29 @@ public TaskRunResult run(Task task) { OperationResult result = task.getResult().createSubresult(WfPropagateTaskObjectReferenceTaskHandler.class + ".run"); - Job job; - try { - job = jobController.recreateJob(task); - } catch (SchemaException e) { - return reportException("Couldn't create a job from task " + task, task, result, e); - } catch (ObjectNotFoundException e) { - return reportException("Couldn't create a job from task " + task, task, result, e); - } + WfTask wfTask = wfTaskController.recreateWfTask(task); - LOGGER.trace("WfPropagateTaskObjectReferenceTaskHandler starting... job = {}", job); + LOGGER.trace("WfPropagateTaskObjectReferenceTaskHandler starting... job = {}", wfTask); ModelContext modelContext; try { - modelContext = job.retrieveModelContext(result); + modelContext = wfTask.retrieveModelContext(result); if (modelContext == null) { - throw new IllegalStateException("There's no model context in the task; job = " + job); + throw new IllegalStateException("There's no model context in the task; job = " + wfTask); } } catch (SchemaException e) { - return reportException("Couldn't retrieve model context from job " + job, task, result, e); + return reportException("Couldn't retrieve model context from job " + wfTask, task, result, e); } catch (ObjectNotFoundException e) { - return reportException("Couldn't retrieve model context from job " + job, task, result, e); + return reportException("Couldn't retrieve model context from job " + wfTask, task, result, e); } catch (CommunicationException e) { - return reportException("Couldn't retrieve model context from job " + job, task, result, TaskRunResult.TaskRunResultStatus.TEMPORARY_ERROR, e); + return reportException("Couldn't retrieve model context from job " + wfTask, task, result, TaskRunResult.TaskRunResultStatus.TEMPORARY_ERROR, e); } catch (ConfigurationException e) { - return reportException("Couldn't retrieve model context from job " + job, task, result, e); + return reportException("Couldn't retrieve model context from job " + wfTask, task, result, e); } String oid = ((LensContext) modelContext).getFocusContext().getOid(); if (oid == null) { - LOGGER.warn("No object OID in job " + job); + LOGGER.warn("No object OID in job " + wfTask); } else { Class typeClass = ((LensContext) modelContext).getFocusContext().getObjectTypeClass(); @@ -130,17 +123,17 @@ public TaskRunResult run(Task task) { LOGGER.warn("object reference in task " + task + " is already set, although it shouldn't be"); } - List dependents; + List dependents; try { - dependents = job.listDependents(result); - dependents.add(job.getParentJob(result)); + dependents = wfTask.listDependents(result); + dependents.add(wfTask.getParentJob(result)); } catch (SchemaException e) { - return reportException("Couldn't get dependents from job " + job, task, result, e); + return reportException("Couldn't get dependents from job " + wfTask, task, result, e); } catch (ObjectNotFoundException e) { - return reportException("Couldn't get dependents from job " + job, task, result, e); + return reportException("Couldn't get dependents from job " + wfTask, task, result, e); } - for (Job dependent : dependents) { + for (WfTask dependent : dependents) { if (dependent.getTask().getObjectRef() == null) { try { dependent.getTask().setObjectRefImmediate(objectReferenceType, result); diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/BasePrimaryChangeAspect.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/BasePrimaryChangeAspect.java index 774c7a063c8..71b871d0ff2 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/BasePrimaryChangeAspect.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/BasePrimaryChangeAspect.java @@ -22,25 +22,23 @@ import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.jobs.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ItemApprovalProcessInterface; import com.evolveum.midpoint.wf.impl.processors.BaseConfigurationHelper; import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpJob; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpWfTask; import com.evolveum.midpoint.wf.impl.processors.primary.PrimaryChangeProcessor; +import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PrimaryChangeProcessorConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; - import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import javax.annotation.PostConstruct; import java.util.List; -import java.util.Map; /** * @author mederly @@ -76,6 +74,9 @@ public abstract class BasePrimaryChangeAspect implements PrimaryChangeAspect, Be @Autowired protected ItemApprovalProcessInterface itemApprovalProcessInterface; + @Autowired + protected MiscDataUtil miscDataUtil; + @PostConstruct public void init() { changeProcessor.registerChangeAspect(this); @@ -91,20 +92,15 @@ public void setBeanName(String name) { } @Override - public ObjectTreeDeltas prepareDeltaOut(ProcessEvent event, PcpJob pcpJob, OperationResult result) throws SchemaException { + public ObjectTreeDeltas prepareDeltaOut(ProcessEvent event, PcpWfTask pcpJob, OperationResult result) throws SchemaException { return primaryChangeAspectHelper.prepareDeltaOut(event, pcpJob, result); } @Override - public List prepareApprovedBy(ProcessEvent event, PcpJob job, OperationResult result) { + public List prepareApprovedBy(ProcessEvent event, PcpWfTask job, OperationResult result) { return processInterfaceFinder.getProcessInterface(event.getVariables()).prepareApprovedBy(event); } - @Override - public ProcessSpecificState externalizeProcessInstanceState(Map variables) { - return processInterfaceFinder.getProcessInterface(variables).externalizeProcessInstanceState(variables); - } - public PrimaryChangeProcessor getChangeProcessor() { return changeProcessor; } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/PrimaryChangeAspect.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/PrimaryChangeAspect.java index 58b5ce8bed9..45d8936ef34 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/PrimaryChangeAspect.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/PrimaryChangeAspect.java @@ -17,26 +17,19 @@ package com.evolveum.midpoint.wf.impl.processors.primary.aspect; import com.evolveum.midpoint.model.api.context.ModelContext; -import com.evolveum.midpoint.prism.Objectable; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildJobCreationInstruction; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpJob; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildWfTaskCreationInstruction; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpWfTask; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.PrimaryChangeProcessorConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.QuestionFormType; -import com.evolveum.midpoint.xml.ns.model.workflow.process_instance_state_3.ProcessSpecificState; import java.util.List; -import java.util.Map; /** * @@ -71,9 +64,9 @@ public interface PrimaryChangeAspect { * @param objectTreeDeltas Change to be examined and modified by implementation of this method * @param taskFromModel General context of the operation - the method should not modify the task. * @param result Operation result - the method should report any errors here (TODO what about creating subresults?) @return list of start process instructions - * @see com.evolveum.midpoint.wf.impl.jobs.JobCreationInstruction + * @see WfTaskCreationInstruction */ - List prepareJobCreationInstructions(ModelContext modelContext, WfConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException, ObjectNotFoundException; + List prepareTasks(ModelContext modelContext, PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException, ObjectNotFoundException; /** * On process instance end, prepares deltaOut based in deltaIn and information gathered during approval process. @@ -86,7 +79,7 @@ public interface PrimaryChangeAspect { * here may be more complex. * @throws SchemaException if there is any problem with the schema. */ - ObjectTreeDeltas prepareDeltaOut(ProcessEvent event, PcpJob job, OperationResult result) throws SchemaException; + ObjectTreeDeltas prepareDeltaOut(ProcessEvent event, PcpWfTask job, OperationResult result) throws SchemaException; /** * Returns a list of users who have approved the particular request. This information is then stored in the task by the wf module, @@ -100,47 +93,7 @@ public interface PrimaryChangeAspect { * @param result Operation result - the method should report any errors here. * @return List of references to approvers that approved this request. */ - List prepareApprovedBy(ProcessEvent event, PcpJob job, OperationResult result); - - /** - * Returns a PrismObject containing information about a work item to be processed by the user. For example, for 'approve role addition' process - * here is the RoleApprovalFormType prism object, having the following items: - * - user: to whom is a role being requested, - * - role: which role was requested to be added, - * - timeInterval: what is the validity time of the assignment that was requested, - * - requesterComment: a text that the requester entered when he requested the operation to be carried out, - * - comment - here the approver writes his comments on approving or rejecting the work item. - * - * @param task activiti task corresponding to the work item that is being displayed - * @param variables process instance variables at the point of invoking the work item (activiti task) - * @param result operation result where the operation status should be reported - * @return PrismObject containing the specific information about work item - * @throws SchemaException if any of key objects cannot be retrieved because of schema exception - * @throws ObjectNotFoundException if any of key objects cannot be found - */ - PrismObject prepareQuestionForm(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException; - - /** - * Returns a object related to the work item at hand. E.g. for 'approve role addition' process this method returns corresponding role object. - * - * @param task activiti task corresponding to the work item that is being displayed - * @param variables process instance variables at the point of invoking the work item (activiti task) - * @param result operation result where the operation status should be reported - * @return PrismObject containing the object related to the work item - * @throws SchemaException if the object cannot be retrieved because of schema exception - * @throws ObjectNotFoundException if the object cannot be found - */ - PrismObject prepareRelatedObject(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException; - - /** - * Externalizes internal state of the process instance. Typically, uninteresting (auxiliary) data elements - * are thrown away, internal representation suitable for workflow processing is replaced by "clean" prism - * object structure, and untyped Map[String,Object] is replaced by typed prism data. - * - * @param variables internal process state represented by a map - * @return external representation - */ - ProcessSpecificState externalizeProcessInstanceState(Map variables); + List prepareApprovedBy(ProcessEvent event, PcpWfTask job, OperationResult result); /** * Returns true if this aspect is enabled by default, i.e. even if not listed in primary change processor configuration. diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/PrimaryChangeAspectHelper.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/PrimaryChangeAspectHelper.java index 99a4f208431..3ab9c3d8676 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/PrimaryChangeAspectHelper.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/aspect/PrimaryChangeAspectHelper.java @@ -23,7 +23,6 @@ import com.evolveum.midpoint.model.common.expression.ExpressionFactory; import com.evolveum.midpoint.model.common.expression.ExpressionVariables; import com.evolveum.midpoint.model.impl.expr.ModelExpressionThreadLocalHolder; -import com.evolveum.midpoint.prism.Objectable; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.PrismPropertyDefinition; @@ -32,7 +31,6 @@ import com.evolveum.midpoint.prism.delta.PrismValueDeltaSetTriple; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.GetOperationOptions; -import com.evolveum.midpoint.schema.SchemaConstantsGenerated; import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; @@ -45,15 +43,12 @@ import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.jobs.WfTaskUtil; +import com.evolveum.midpoint.wf.impl.tasks.WfTaskUtil; import com.evolveum.midpoint.wf.impl.messages.ProcessEvent; -import com.evolveum.midpoint.wf.impl.processes.common.SpringApplicationContextHolder; import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpJob; -import com.evolveum.midpoint.wf.impl.processors.primary.entitlements.AddAssociationAspect; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpWfTask; import com.evolveum.midpoint.wf.util.ApprovalUtils; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import org.activiti.engine.delegate.DelegateExecution; import org.apache.velocity.util.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -63,9 +58,7 @@ import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; /** * @author mederly @@ -100,7 +93,7 @@ public class PrimaryChangeAspectHelper { * DeltaIn contains a delta that has to be approved. Workflow answers simply yes/no. * Therefore, we either copy DeltaIn to DeltaOut, or generate an empty list of modifications. */ - public ObjectTreeDeltas prepareDeltaOut(ProcessEvent event, PcpJob pcpJob, OperationResult result) throws SchemaException { + public ObjectTreeDeltas prepareDeltaOut(ProcessEvent event, PcpWfTask pcpJob, OperationResult result) throws SchemaException { ObjectTreeDeltas deltaIn = pcpJob.retrieveDeltasToProcess(); if (ApprovalUtils.isApproved(event.getAnswer())) { return deltaIn; @@ -111,19 +104,6 @@ public ObjectTreeDeltas prepareDeltaOut(ProcessEvent event, PcpJob pcpJob, Opera //endregion - //region ========================================================================== Miscellaneous - public String getObjectOid(ModelContext modelContext) { - ModelElementContext fc = (ModelElementContext) modelContext.getFocusContext(); - String objectOid = null; - if (fc.getObjectNew() != null && fc.getObjectNew().getOid() != null) { - return fc.getObjectNew().getOid(); - } else if (fc.getObjectOld() != null && fc.getObjectOld().getOid() != null) { - return fc.getObjectOld().getOid(); - } else { - return null; - } - } - public PrismObject getRequester(Task task, OperationResult result) { // let's get fresh data (not the ones read on user login) PrismObject requester = null; diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/assignments/AddAssignmentAspect.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/assignments/AddAssignmentAspect.java index f2903d2177f..2c0ee94f57a 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/assignments/AddAssignmentAspect.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/assignments/AddAssignmentAspect.java @@ -22,7 +22,6 @@ import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ContainerDelta; import com.evolveum.midpoint.prism.delta.ItemDelta; @@ -30,37 +29,28 @@ import com.evolveum.midpoint.prism.path.ItemPath; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.processes.addrole.AddRoleVariableNames; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequest; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ItemApprovalProcessInterface; -import com.evolveum.midpoint.wf.impl.processes.itemApproval.ProcessVariableNames; +import com.evolveum.midpoint.wf.impl.processes.itemApproval.ItemApprovalSpecificContent; import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildJobCreationInstruction; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildWfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.processors.primary.PrimaryChangeProcessor; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.BasePrimaryChangeAspect; -import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PcpAspectConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.AssignmentCreationApprovalFormType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.QuestionFormType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.xml.datatype.XMLGregorianCalendar; -import java.text.DateFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Map; + +import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.createObjectRef; +import static com.evolveum.midpoint.wf.impl.util.MiscDataUtil.getFocusObjectName; +import static com.evolveum.midpoint.wf.impl.util.MiscDataUtil.getFocusObjectOid; /** * Aspect for adding assignments of any type (abstract role or resource). @@ -87,7 +77,7 @@ public abstract class AddAssignmentAspect prepareJobCreationInstructions(ModelContext modelContext, WfConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException { + public List prepareTasks(ModelContext modelContext, PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException { if (!isFocusRelevant(modelContext) || objectTreeDeltas.getFocusChange() == null) { return null; } @@ -95,22 +85,23 @@ public List prepareJobCreationInstructions(Model if (approvalRequestList == null || approvalRequestList.isEmpty()) { return null; } - return prepareJobCreateInstructions(modelContext, taskFromModel, result, approvalRequestList); + return prepareTaskInstructions(modelContext, taskFromModel, result, approvalRequestList); } - private List> getApprovalRequests(ModelContext modelContext, WfConfigurationType wfConfigurationType, ObjectDelta change, OperationResult result) { + private List> getApprovalRequests(ModelContext modelContext, PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectDelta change, OperationResult result) { if (change.getChangeType() != ChangeType.ADD && change.getChangeType() != ChangeType.MODIFY) { return null; } PcpAspectConfigurationType config = primaryChangeAspectHelper.getPcpAspectConfigurationType(wfConfigurationType, this); if (change.getChangeType() == ChangeType.ADD) { - return getApprovalRequestsFromFocusAdd(config, change, result); + return getApprovalRequestsFromFocusAdd(config, change, modelContext, result); } else { return getApprovalRequestsFromFocusModify(config, modelContext.getFocusContext().getObjectOld(), change, result); } } - private List> getApprovalRequestsFromFocusAdd(PcpAspectConfigurationType config, ObjectDelta change, OperationResult result) { + private List> getApprovalRequestsFromFocusAdd(PcpAspectConfigurationType config, ObjectDelta change, + ModelContext modelContext, OperationResult result) { LOGGER.trace("Relevant assignments in focus add delta:"); List> approvalRequestList = new ArrayList<>(); @@ -126,6 +117,7 @@ private List> getApprovalRequestsFromFocusAdd(Pc AssignmentType aCopy = cloneAndCanonicalizeAssignment(a); approvalRequestList.add(createApprovalRequest(config, aCopy, specificObjectType)); assignmentTypeIterator.remove(); + miscDataUtil.generateFocusOidIfNeeded(modelContext, change); } } } @@ -133,7 +125,7 @@ private List> getApprovalRequestsFromFocusAdd(Pc } private List> getApprovalRequestsFromFocusModify(PcpAspectConfigurationType config, - PrismObject focusOld, + PrismObject focusOld, ObjectDelta change, OperationResult result) { LOGGER.trace("Relevant assignments in focus modify delta:"); @@ -190,7 +182,7 @@ private List> getApprovalRequestsFromFocusModify return approvalRequestList; } - private boolean existsEquivalentValue(PrismObject focusOld, PrismContainerValue assignmentValue) { + private boolean existsEquivalentValue(PrismObject focusOld, PrismContainerValue assignmentValue) { FocusType focusType = (FocusType) focusOld.asObjectable(); for (AssignmentType existing : focusType.getAssignment()) { if (existing.asPrismContainerValue().equalsRealValue(assignmentValue)) { @@ -214,12 +206,12 @@ private ApprovalRequest processAssignmentToAdd(PcpAspectConfigur return null; } - private List prepareJobCreateInstructions(ModelContext modelContext, Task taskFromModel, - OperationResult result, List> approvalRequestList) throws SchemaException { + private List prepareTaskInstructions(ModelContext modelContext, Task taskFromModel, + OperationResult result, List> approvalRequestList) throws SchemaException { - List instructions = new ArrayList<>(); - String assigneeName = MiscDataUtil.getFocusObjectName(modelContext); - String assigneeOid = primaryChangeAspectHelper.getObjectOid(modelContext); + List instructions = new ArrayList<>(); + String assigneeOid = getFocusObjectOid(modelContext); + String assigneeName = getFocusObjectName(modelContext); PrismObject requester = primaryChangeAspectHelper.getRequester(taskFromModel, result); for (ApprovalRequest approvalRequest : approvalRequestList) { @@ -232,29 +224,24 @@ private List prepareJobCreateInstructions(ModelC Validate.notNull(target, "No target in assignment to be approved"); String targetName = target.getName() != null ? target.getName().getOrig() : "(unnamed)"; + String approvalTaskName = "Approve adding " + targetName + " to " + assigneeName; - // create a JobCreateInstruction for a given change processor (primaryChangeProcessor in this case) - PcpChildJobCreationInstruction instruction = - PcpChildJobCreationInstruction.createInstruction(getChangeProcessor()); + PcpChildWfTaskCreationInstruction instruction = + PcpChildWfTaskCreationInstruction.createItemApprovalInstruction(getChangeProcessor(), approvalTaskName, approvalRequest); - // set some common task/process attributes - instruction.prepareCommonAttributes(this, modelContext, assigneeOid, requester); + instruction.prepareCommonAttributes(this, modelContext, requester); - // prepare and set the delta that has to be approved - ObjectDelta delta = assignmentToDelta(modelContext, assignmentType, assigneeOid); - instruction.setDeltaProcessAndTaskVariables(delta); + ObjectDelta delta = assignmentToDelta(modelContext, assignmentType, assigneeOid); + instruction.setDeltasToProcess(delta); + + instruction.setObjectRef(modelContext, result); + instruction.setTargetRef(createObjectRef(target), result); - // set the names of midPoint task and activiti process instance String andExecuting = instruction.isExecuteApprovedChangeImmediately() ? "and executing " : ""; instruction.setTaskName("Workflow for approving " + andExecuting + "adding " + targetName + " to " + assigneeName); instruction.setProcessInstanceName("Adding " + targetName + " to " + assigneeName); - // setup general item approval process - String approvalTaskName = "Approve adding " + targetName + " to " + assigneeName; - itemApprovalProcessInterface.prepareStartInstruction(instruction, approvalRequest, approvalTaskName); - - // set some aspect-specific variables - instruction.addProcessVariable(AddRoleVariableNames.FOCUS_NAME, assigneeName); + itemApprovalProcessInterface.prepareStartInstruction(instruction); instructions.add(instruction); } @@ -262,7 +249,8 @@ private List prepareJobCreateInstructions(ModelC } // creates an ObjectDelta that will be executed after successful approval of the given assignment - private ObjectDelta assignmentToDelta(ModelContext modelContext, AssignmentType assignmentType, String objectOid) { + @SuppressWarnings("unchecked") + private ObjectDelta assignmentToDelta(ModelContext modelContext, AssignmentType assignmentType, String objectOid) { PrismObject focus = (PrismObject) modelContext.getFocusContext().getObjectNew(); PrismContainerDefinition prismContainerDefinition = focus.getDefinition().findContainerDefinition(FocusType.F_ASSIGNMENT); @@ -271,82 +259,9 @@ private ObjectDelta assignmentToDelta(ModelContext mode addRoleDelta.addValueToAdd(assignmentValue); Class focusClass = primaryChangeAspectHelper.getFocusClass(modelContext); - String focusOid = objectOid != null ? objectOid : PrimaryChangeProcessor.UNKNOWN_OID; - return ObjectDelta.createModifyDelta(focusOid, addRoleDelta, focusClass, ((LensContext) modelContext).getPrismContext()); - } - - //endregion - - //region ------------------------------------------------------------ Things that execute when item is being approved - - @Override - public PrismObject prepareQuestionForm(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("prepareQuestionForm starting: execution id {}, pid {}, variables = {}", task.getExecutionId(), task.getProcessInstanceId(), variables); - } - - // todo check type compatibility - ApprovalRequest request = (ApprovalRequest) variables.get(ProcessVariableNames.APPROVAL_REQUEST); - request.setPrismContext(prismContext); - Validate.notNull(request, "Approval request is not present among process variables"); - - AssignmentType assignment = (AssignmentType) request.getItemToApprove(); - Validate.notNull(assignment, "Approval request does not contain as assignment"); - - T target = getAssignmentApprovalTarget(assignment, result); // may throw an (unchecked) exception - - PrismObjectDefinition formDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByType(AssignmentCreationApprovalFormType.COMPLEX_TYPE); - PrismObject formPrism = formDefinition.instantiate(); - AssignmentCreationApprovalFormType form = formPrism.asObjectable(); - - String focusName = (String) variables.get(AddRoleVariableNames.FOCUS_NAME); - form.setFocusName(focusName); // TODO disginguish somehow between users/roles/orgs - form.setAssignedObjectName(getTargetDisplayName(target)); - form.setRequesterComment(assignment.getDescription()); - form.setTimeInterval(formatTimeIntervalBrief(assignment)); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Resulting prism object instance = {}", formPrism.debugDump()); - } - return formPrism; + return ObjectDelta.createModifyDelta(objectOid, addRoleDelta, focusClass, ((LensContext) modelContext).getPrismContext()); } - public static String formatTimeIntervalBrief(AssignmentType assignment) { - StringBuilder sb = new StringBuilder(); - if (assignment != null && assignment.getActivation() != null && - (assignment.getActivation().getValidFrom() != null || assignment.getActivation().getValidTo() != null)) { - if (assignment.getActivation().getValidFrom() != null && assignment.getActivation().getValidTo() != null) { - sb.append(formatTime(assignment.getActivation().getValidFrom())); - sb.append("-"); - sb.append(formatTime(assignment.getActivation().getValidTo())); - } else if (assignment.getActivation().getValidFrom() != null) { - sb.append("from "); - sb.append(formatTime(assignment.getActivation().getValidFrom())); - } else { - sb.append("to "); - sb.append(formatTime(assignment.getActivation().getValidTo())); - } - } - return sb.toString(); - } - - private static String formatTime(XMLGregorianCalendar time) { - DateFormat formatter = DateFormat.getDateInstance(); - return formatter.format(time.toGregorianCalendar().getTime()); - } - - @Override - public PrismObject prepareRelatedObject(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - - ApprovalRequest approvalRequest = (ApprovalRequest) variables.get(ProcessVariableNames.APPROVAL_REQUEST); - approvalRequest.setPrismContext(prismContext); - if (approvalRequest == null) { - throw new IllegalStateException("No approval request in activiti task " + task); - } - T target = getAssignmentApprovalTarget(approvalRequest.getItemToApprove(), result); - return target != null ? target.asPrismObject() : null; - } //endregion //region ------------------------------------------------------------ Things to override in concrete aspect classes diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/assignments/ModifyAssignmentAspect.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/assignments/ModifyAssignmentAspect.java index 2634a26e98b..4faada0c331 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/assignments/ModifyAssignmentAspect.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/assignments/ModifyAssignmentAspect.java @@ -22,7 +22,6 @@ import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; @@ -31,41 +30,25 @@ import com.evolveum.midpoint.prism.path.ItemPathSegment; import com.evolveum.midpoint.schema.DeltaConvertor; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.processes.addrole.AddRoleVariableNames; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequest; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ItemApprovalProcessInterface; -import com.evolveum.midpoint.wf.impl.processes.itemApproval.ProcessVariableNames; import com.evolveum.midpoint.wf.impl.processes.modifyAssignment.AssignmentModification; import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildJobCreationInstruction; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildWfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.BasePrimaryChangeAspect; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PcpAspectConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.AssignmentModificationApprovalFormType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.QuestionFormType; -import com.evolveum.prism.xml.ns._public.types_3.ChangeTypeType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ItemDeltaType; -import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Change aspect that manages assignment modification approval. @@ -92,7 +75,7 @@ public abstract class ModifyAssignmentAspect prepareJobCreationInstructions(ModelContext modelContext, WfConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException { + public List prepareTasks(ModelContext modelContext, PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException { if (!isFocusRelevant(modelContext) || objectTreeDeltas.getFocusChange() == null) { return null; } @@ -103,7 +86,7 @@ public List prepareJobCreationInstructions(Model return prepareJobCreateInstructions(modelContext, taskFromModel, result, approvalRequestList); } - private List> getApprovalRequests(ModelContext modelContext, WfConfigurationType wfConfigurationType, ObjectDelta change, OperationResult result) throws SchemaException { + private List> getApprovalRequests(ModelContext modelContext, PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectDelta change, OperationResult result) throws SchemaException { if (change.getChangeType() != ChangeType.MODIFY) { return null; } @@ -199,8 +182,8 @@ public static AssignmentType getAssignmentToBeModified(PrismContainer prepareJobCreateInstructions(ModelContext modelContext, Task taskFromModel, OperationResult result, List> approvalRequestList) throws SchemaException { - List instructions = new ArrayList<>(); + private List prepareJobCreateInstructions(ModelContext modelContext, Task taskFromModel, OperationResult result, List> approvalRequestList) throws SchemaException { + List instructions = new ArrayList<>(); String focusName = MiscDataUtil.getFocusObjectName(modelContext); @@ -218,19 +201,24 @@ private List prepareJobCreateInstructions(ModelC Validate.notNull(target); String targetName = getTargetDisplayName(target); - String focusOid = primaryChangeAspectHelper.getObjectOid(modelContext); + String focusOid = MiscDataUtil.getFocusObjectOid(modelContext); PrismObject requester = primaryChangeAspectHelper.getRequester(taskFromModel, result); + String approvalTaskName = "Approve modifying assignment of " + targetName + " to " + focusName; + // create a JobCreateInstruction for a given change processor (primaryChangeProcessor in this case) - PcpChildJobCreationInstruction instruction = - PcpChildJobCreationInstruction.createInstruction(getChangeProcessor()); + PcpChildWfTaskCreationInstruction instruction = + PcpChildWfTaskCreationInstruction.createItemApprovalInstruction(getChangeProcessor(), approvalTaskName, approvalRequest); // set some common task/process attributes - instruction.prepareCommonAttributes(this, modelContext, focusOid, requester); + instruction.prepareCommonAttributes(this, modelContext, requester); // prepare and set the delta that has to be approved ObjectDelta delta = requestToDelta(modelContext, approvalRequest, focusOid); - instruction.setDeltaProcessAndTaskVariables(delta); + instruction.setDeltasToProcess(delta); + + instruction.setObjectRef(modelContext, result); + instruction.setTargetRef(ObjectTypeUtil.createObjectRef(target), result); // set the names of midPoint task and activiti process instance String andExecuting = instruction.isExecuteApprovedChangeImmediately() ? "and executing " : ""; @@ -238,11 +226,7 @@ private List prepareJobCreateInstructions(ModelC instruction.setProcessInstanceName("Modifying assignment of " + targetName + " to " + focusName); // setup general item approval process - String approvalTaskName = "Approve modifying assignment of " + targetName + " to " + focusName; - itemApprovalProcessInterface.prepareStartInstruction(instruction, approvalRequest, approvalTaskName); - - // set some aspect-specific variables - instruction.addProcessVariable(AddRoleVariableNames.FOCUS_NAME, focusName); + itemApprovalProcessInterface.prepareStartInstruction(instruction); instructions.add(instruction); } @@ -261,58 +245,6 @@ private ObjectDelta requestToDelta(ModelContext modelCo //region ------------------------------------------------------------ Things that execute when item is being approved - @Override - public PrismObject prepareQuestionForm(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("prepareQuestionForm starting: execution id {}, pid {}, variables = {}", task.getExecutionId(), task.getProcessInstanceId(), variables); - } - - PrismObjectDefinition formDefinition = - prismContext.getSchemaRegistry().findObjectDefinitionByType(AssignmentModificationApprovalFormType.COMPLEX_TYPE); - PrismObject formPrism = formDefinition.instantiate(); - AssignmentModificationApprovalFormType form = formPrism.asObjectable(); - - form.setFocusName((String) variables.get(AddRoleVariableNames.FOCUS_NAME)); // TODO disginguish somehow between users/roles/orgs - - // todo check type compatibility - ApprovalRequest request = (ApprovalRequest) variables.get(ProcessVariableNames.APPROVAL_REQUEST); - request.setPrismContext(prismContext); - Validate.notNull(request, "Approval request is not present among process variables"); - - AssignmentModification itemToApprove = (AssignmentModification) request.getItemToApprove(); - Validate.notNull(itemToApprove, "Approval request does not contain an item to approve"); - - T target = (T) itemToApprove.getTarget(); // TODO shouldn't we retrieve fresh value from repo? - String targetDisplayName = getTargetDisplayName(target); - form.setAssignedObjectName(targetDisplayName); - //TODO form.setRequesterComment(itemToApprove.getDescription()); - - ObjectDeltaType objectDeltaType = new ObjectDeltaType(); - objectDeltaType.setOid("?"); - objectDeltaType.setChangeType(ChangeTypeType.MODIFY); - objectDeltaType.setObjectType(UserType.COMPLEX_TYPE); // TODO - objectDeltaType.getItemDelta().addAll(itemToApprove.getModifications()); - form.setModification(objectDeltaType); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Resulting prism object instance = {}", formPrism.debugDump()); - } - return formPrism; - } - - @Override - public PrismObject prepareRelatedObject(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - - ApprovalRequest approvalRequest = (ApprovalRequest) - variables.get(ProcessVariableNames.APPROVAL_REQUEST); - approvalRequest.setPrismContext(prismContext); - if (approvalRequest == null) { - throw new IllegalStateException("No approval request in activiti task " + task); - } - - return approvalRequest.getItemToApprove().getTarget().asPrismObject(); - } //endregion diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/entitlements/AddAssociationAspect.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/entitlements/AddAssociationAspect.java index b282c95e289..63cc47de76c 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/entitlements/AddAssociationAspect.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/entitlements/AddAssociationAspect.java @@ -22,7 +22,6 @@ import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismContext; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.delta.ItemDelta; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.delta.builder.DeltaBuilder; @@ -30,36 +29,29 @@ import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.processes.addrole.AddRoleVariableNames; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequest; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequestImpl; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ItemApprovalProcessInterface; -import com.evolveum.midpoint.wf.impl.processes.itemApproval.ProcessVariableNames; import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildJobCreationInstruction; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildWfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.BasePrimaryChangeAspect; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.PrimaryChangeAspectHelper; import com.evolveum.midpoint.wf.impl.processors.primary.assignments.AssignmentHelper; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.AssociationCreationApprovalFormType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.QuestionFormType; import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.xml.datatype.XMLGregorianCalendar; import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * Aspect for adding associations. @@ -88,7 +80,7 @@ public class AddAssociationAspect extends BasePrimaryChangeAspect { //region ------------------------------------------------------------ Things that execute on request arrival @Override - public List prepareJobCreationInstructions(ModelContext modelContext, WfConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException, ObjectNotFoundException { + public List prepareTasks(ModelContext modelContext, PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException, ObjectNotFoundException { if (!isFocusRelevant(modelContext)) { return null; } @@ -105,7 +97,7 @@ protected boolean isFocusRelevant(ModelContext modelContext) { return true; } - private List> getApprovalRequests(ModelContext modelContext, WfConfigurationType wfConfigurationType, + private List> getApprovalRequests(ModelContext modelContext, PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectTreeDeltas changes, Task taskFromModel, OperationResult result) { List> requests = new ArrayList<>(); @@ -141,6 +133,7 @@ private List> getApprovalRequests(Model if (isAssociationRelevant(config, itemToApprove, rsd, modelContext, taskFromModel, result)) { approvalRequestList.add(createApprovalRequest(config, itemToApprove)); associationIterator.remove(); + miscDataUtil.generateProjectionOidIfNeeded(modelContext, shadowType, rsd); } } return approvalRequestList; @@ -231,14 +224,14 @@ private boolean existsEquivalentValue(PrismObject shadowOld, PrismCo } } - private List + private List prepareJobCreateInstructions(ModelContext modelContext, Task taskFromModel, OperationResult result, List> approvalRequestList) throws SchemaException, ObjectNotFoundException { - List instructions = new ArrayList<>(); + List instructions = new ArrayList<>(); String assigneeName = MiscDataUtil.getFocusObjectName(modelContext); - String assigneeOid = primaryChangeAspectHelper.getObjectOid(modelContext); + String assigneeOid = MiscDataUtil.getFocusObjectOid(modelContext); PrismObject requester = primaryChangeAspectHelper.getRequester(taskFromModel, result); for (ApprovalRequest approvalRequest : approvalRequestList) { @@ -253,16 +246,21 @@ private boolean existsEquivalentValue(PrismObject shadowOld, PrismCo String targetName = target.getName() != null ? target.getName().getOrig() : "(unnamed)"; + String approvalTaskName = "Approve adding " + targetName + " to " + assigneeName; + // create a JobCreateInstruction for a given change processor (primaryChangeProcessor in this case) - PcpChildJobCreationInstruction instruction = - PcpChildJobCreationInstruction.createInstruction(getChangeProcessor()); + PcpChildWfTaskCreationInstruction instruction = + PcpChildWfTaskCreationInstruction.createItemApprovalInstruction(getChangeProcessor(), approvalTaskName, approvalRequest); // set some common task/process attributes - instruction.prepareCommonAttributes(this, modelContext, assigneeOid, requester); + instruction.prepareCommonAttributes(this, modelContext, requester); // prepare and set the delta that has to be approved ObjectTreeDeltas objectTreeDeltas = associationAdditionToDelta(modelContext, associationAddition, assigneeOid); - instruction.setObjectTreeDeltasProcessAndTaskVariables(objectTreeDeltas); + instruction.setDeltasToProcesses(objectTreeDeltas); + + instruction.setObjectRef(modelContext, result); // TODO - or should we take shadow as an object? + instruction.setTargetRef(ObjectTypeUtil.createObjectRef(target), result); // set the names of midPoint task and activiti process instance String andExecuting = instruction.isExecuteApprovedChangeImmediately() ? "and executing " : ""; @@ -270,11 +268,7 @@ private boolean existsEquivalentValue(PrismObject shadowOld, PrismCo instruction.setProcessInstanceName("Adding " + targetName + " to " + assigneeName); // setup general item approval process - String approvalTaskName = "Approve adding " + targetName + " to " + assigneeName; - itemApprovalProcessInterface.prepareStartInstruction(instruction, approvalRequest, approvalTaskName); - - // set some aspect-specific variables - instruction.addProcessVariable(AddRoleVariableNames.FOCUS_NAME, assigneeName); + itemApprovalProcessInterface.prepareStartInstruction(instruction); instructions.add(instruction); } @@ -288,7 +282,7 @@ private ObjectTreeDeltas associationAdditionToDelta(ModelContext modelContext ResourceShadowDiscriminator shadowDiscriminator = ResourceShadowDiscriminator.fromResourceShadowDiscriminatorType(addition.getResourceShadowDiscriminator()); String projectionOid = modelContext.findProjectionContext(shadowDiscriminator).getOid(); - ObjectDelta objectDelta = DeltaBuilder.deltaFor(ShadowType.class, prismContext) + ObjectDelta objectDelta = (ObjectDelta) DeltaBuilder.deltaFor(ShadowType.class, prismContext) .item(ShadowType.F_ASSOCIATION).add(addition.getAssociation().clone()) .asObjectDelta(projectionOid); @@ -300,46 +294,11 @@ private ObjectTreeDeltas associationAdditionToDelta(ModelContext modelContext //region ------------------------------------------------------------ Things that execute when item is being approved - @Override - public PrismObject prepareQuestionForm(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("prepareQuestionForm starting: execution id {}, pid {}, variables = {}", task.getExecutionId(), task.getProcessInstanceId(), variables); - } - - // todo check type compatibility - ApprovalRequest request = (ApprovalRequest) variables.get(ProcessVariableNames.APPROVAL_REQUEST); - request.setPrismContext(prismContext); - Validate.notNull(request, "Approval request is not present among process variables"); - - AssociationAdditionType aat = (AssociationAdditionType) request.getItemToApprove(); - Validate.notNull(aat, "Approval request does not contain the association addition information"); - - ShadowType target = getAssociationApprovalTarget(aat.getAssociation(), result); // may throw an (unchecked) exception - - PrismObjectDefinition formDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByType(AssociationCreationApprovalFormType.COMPLEX_TYPE); - PrismObject formPrism = formDefinition.instantiate(); - AssociationCreationApprovalFormType form = formPrism.asObjectable(); - - String focusName = (String) variables.get(AddRoleVariableNames.FOCUS_NAME); - form.setFocusName(focusName); // TODO distinguish somehow between users/roles/orgs - form.setAssociatedObjectName(getTargetDisplayName(target)); - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Resulting prism object instance = {}", formPrism.debugDump()); - } - return formPrism; - } - private static String formatTime(XMLGregorianCalendar time) { DateFormat formatter = DateFormat.getDateInstance(); return formatter.format(time.toGregorianCalendar().getTime()); } - @Override - public PrismObject prepareRelatedObject(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - return null; - } //endregion protected boolean isAssociationRelevant(PcpAspectConfigurationType config, AssociationAdditionType itemToApprove, diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/objects/AddObjectAspect.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/objects/AddObjectAspect.java index 720ddc50107..9362368bfda 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/objects/AddObjectAspect.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/objects/AddObjectAspect.java @@ -17,34 +17,27 @@ package com.evolveum.midpoint.wf.impl.processors.primary.objects; import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.impl.lens.LensFocusContext; import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismObjectDefinition; import com.evolveum.midpoint.prism.delta.ChangeType; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.OidUtil; import com.evolveum.midpoint.task.api.Task; -import com.evolveum.midpoint.util.exception.ObjectNotFoundException; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequest; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequestImpl; -import com.evolveum.midpoint.wf.impl.processes.itemApproval.ProcessVariableNames; import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildJobCreationInstruction; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildWfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.BasePrimaryChangeAspect; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PcpAspectConfigurationType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.AddObjectApprovalFormType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.QuestionFormType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang.Validate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; /** * Change aspect that manages addition of an object. @@ -61,8 +54,8 @@ public abstract class AddObjectAspect extends BasePrimaryC protected abstract String getObjectLabel(T object); @Override - public List prepareJobCreationInstructions(ModelContext modelContext, - WfConfigurationType wfConfigurationType, + public List prepareTasks(ModelContext modelContext, + PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException { PcpAspectConfigurationType config = primaryChangeAspectHelper.getPcpAspectConfigurationType(wfConfigurationType, this); @@ -85,6 +78,11 @@ private List> getApprovalRequests(ModelContext modelContex return null; } T objectType = (T) change.getObjectToAdd().asObjectable().clone(); + if (objectType.getOid() == null) { + String newOid = OidUtil.generateOid(); + objectType.setOid(newOid); + ((LensFocusContext) modelContext.getFocusContext()).setOid(newOid); + } change.setObjectToAdd(null); // make the change empty return Arrays.asList(createApprovalRequest(config, objectType)); } @@ -95,9 +93,9 @@ private ApprovalRequest createApprovalRequest(PcpAspectConfigurationType conf return new ApprovalRequestImpl(objectType, config, prismContext); } - private List prepareJobCreateInstructions(ModelContext modelContext, Task taskFromModel, OperationResult result, + private List prepareJobCreateInstructions(ModelContext modelContext, Task taskFromModel, OperationResult result, List> approvalRequestList) throws SchemaException { - List instructions = new ArrayList<>(); + List instructions = new ArrayList<>(); for (ApprovalRequest approvalRequest : approvalRequestList) { // there should be just one @@ -111,16 +109,21 @@ private List prepareJobCreateInstructions(ModelC PrismObject requester = primaryChangeAspectHelper.getRequester(taskFromModel, result); + String approvalTaskName = "Approve creating " + objectLabel; + // create a JobCreateInstruction for a given change processor (primaryChangeProcessor in this case) - PcpChildJobCreationInstruction instruction = - PcpChildJobCreationInstruction.createInstruction(getChangeProcessor()); + PcpChildWfTaskCreationInstruction instruction = + PcpChildWfTaskCreationInstruction.createItemApprovalInstruction(getChangeProcessor(), approvalTaskName, approvalRequest); // set some common task/process attributes - instruction.prepareCommonAttributes(this, modelContext, null, requester); // objectOid is null (because object does not exist yet) + instruction.prepareCommonAttributes(this, modelContext, requester); // prepare and set the delta that has to be approved ObjectDelta delta = assignmentToDelta(modelContext); - instruction.setDeltaProcessAndTaskVariables(delta); + instruction.setDeltasToProcess(delta); + + instruction.setObjectRef(modelContext, result); + instruction.setTargetRef(null, result); // set the names of midPoint task and activiti process instance String andExecuting = instruction.isExecuteApprovedChangeImmediately() ? "and executing " : ""; @@ -128,15 +131,14 @@ private List prepareJobCreateInstructions(ModelC instruction.setProcessInstanceName("Creating " + objectLabel); // setup general item approval process - String approvalTaskName = "Approve creating " + objectLabel; - itemApprovalProcessInterface.prepareStartInstruction(instruction, approvalRequest, approvalTaskName); + itemApprovalProcessInterface.prepareStartInstruction(instruction); instructions.add(instruction); } return instructions; } - private ObjectDelta assignmentToDelta(ModelContext modelContext) { + private ObjectDelta assignmentToDelta(ModelContext modelContext) { return modelContext.getFocusContext().getPrimaryDelta(); } @@ -144,38 +146,5 @@ private ObjectDelta assignmentToDelta(ModelContext mode //region ------------------------------------------------------------ Things that execute when item is being approved - @Override - public PrismObject prepareQuestionForm(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("getRequestSpecific starting: execution id {}, pid {}, variables = {}", task.getExecutionId(), task.getProcessInstanceId(), variables); - } - - PrismObjectDefinition formDefinition = prismContext.getSchemaRegistry().findObjectDefinitionByType(AddObjectApprovalFormType.COMPLEX_TYPE); - PrismObject formPrism = formDefinition.instantiate(); - AddObjectApprovalFormType form = formPrism.asObjectable(); - - ApprovalRequest request = (ApprovalRequest) variables.get(ProcessVariableNames.APPROVAL_REQUEST); - request.setPrismContext(prismContext); - Validate.notNull(request, "Approval request is not present among process variables"); - form.setObjectToAdd(getObjectLabel(request.getItemToApprove())); - - form.setRequesterComment(null); // TODO - - if (LOGGER.isTraceEnabled()) { - LOGGER.trace("Resulting prism object instance = {}", formPrism.debugDump()); - } - return formPrism; - } - - @Override - public PrismObject prepareRelatedObject(org.activiti.engine.task.Task task, Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - - ApprovalRequest request = (ApprovalRequest) variables.get(ProcessVariableNames.APPROVAL_REQUEST); - request.setPrismContext(prismContext); - Validate.notNull(request, "Approval request is not present among process variables"); - return request.getItemToApprove().asPrismObject(); - } - //endregion } \ No newline at end of file diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/other/ChangePasswordAspect.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/other/ChangePasswordAspect.java index be28d0693c1..839297afc32 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/other/ChangePasswordAspect.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processors/primary/other/ChangePasswordAspect.java @@ -29,30 +29,20 @@ import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; -import com.evolveum.midpoint.wf.impl.processes.addrole.AddRoleVariableNames; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequest; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ApprovalRequestImpl; import com.evolveum.midpoint.wf.impl.processes.itemApproval.ItemApprovalProcessInterface; import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildJobCreationInstruction; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpChildWfTaskCreationInstruction; import com.evolveum.midpoint.wf.impl.processors.primary.aspect.BasePrimaryChangeAspect; import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; -import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.PasswordType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.SystemObjectsType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WfConfigurationType; -import com.evolveum.midpoint.xml.ns.model.workflow.common_forms_3.QuestionFormType; - +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Map; /** * This is a preliminary version of 'password approval' process aspect. The idea is that in some cases, a user may request @@ -78,10 +68,10 @@ public class ChangePasswordAspect extends BasePrimaryChangeAspect { private ItemApprovalProcessInterface itemApprovalProcessInterface; @Override - public List prepareJobCreationInstructions(ModelContext modelContext, WfConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException { + public List prepareTasks(ModelContext modelContext, PrimaryChangeProcessorConfigurationType wfConfigurationType, ObjectTreeDeltas objectTreeDeltas, Task taskFromModel, OperationResult result) throws SchemaException { - List> approvalRequestList = new ArrayList>(); - List instructions = new ArrayList<>(); + List> approvalRequestList = new ArrayList<>(); + List instructions = new ArrayList<>(); ObjectDelta changeRequested = objectTreeDeltas.getFocusChange(); @@ -110,16 +100,6 @@ public List prepareJobCreationInstructions(Model return instructions; } - @Override - public PrismObject prepareQuestionForm(org.activiti.engine.task.Task task, Map variables, OperationResult result) { - return null; // todo implement this - } - - @Override - public PrismObject prepareRelatedObject(org.activiti.engine.task.Task task, Map variables, OperationResult result) { - return null; // todo implement this - } - private ApprovalRequest createApprovalRequest(ItemDelta delta) { ObjectReferenceType approverRef = new ObjectReferenceType(); @@ -132,32 +112,33 @@ private ApprovalRequest createApprovalRequest(ItemDelta delta) { return new ApprovalRequestImpl("Password change", null, null, approvers, null, null, prismContext); } - private PcpChildJobCreationInstruction createStartProcessInstruction(ModelContext modelContext, ItemDelta delta, ApprovalRequest approvalRequest, Task taskFromModel, OperationResult result) throws SchemaException { + private PcpChildWfTaskCreationInstruction createStartProcessInstruction(ModelContext modelContext, ItemDelta delta, ApprovalRequest approvalRequest, Task taskFromModel, OperationResult result) throws SchemaException { String userName = MiscDataUtil.getFocusObjectName(modelContext); - String objectOid = primaryChangeAspectHelper.getObjectOid(modelContext); + String objectOid = MiscDataUtil.getFocusObjectOid(modelContext); PrismObject requester = primaryChangeAspectHelper.getRequester(taskFromModel, result); + String approvalTaskName = "Approve changing password for " + userName; + // create a JobCreateInstruction for a given change processor (primaryChangeProcessor in this case) - PcpChildJobCreationInstruction instruction = - PcpChildJobCreationInstruction.createInstruction(getChangeProcessor()); + PcpChildWfTaskCreationInstruction instruction = + PcpChildWfTaskCreationInstruction.createItemApprovalInstruction(getChangeProcessor(), approvalTaskName, approvalRequest); // set some common task/process attributes - instruction.prepareCommonAttributes(this, modelContext, objectOid, requester); + instruction.prepareCommonAttributes(this, modelContext, requester); // prepare and set the delta that has to be approved - instruction.setDeltaProcessAndTaskVariables(itemDeltaToObjectDelta(objectOid, delta)); + instruction.setDeltasToProcess(itemDeltaToObjectDelta(objectOid, delta)); + + instruction.setObjectRef(modelContext, result); + instruction.setTargetRef(null, result); // set the names of midPoint task and activiti process instance instruction.setTaskName("Workflow for approving password change for " + userName); instruction.setProcessInstanceName("Changing password for " + userName); // setup general item approval process - String approvalTaskName = "Approve changing password for " + userName; - itemApprovalProcessInterface.prepareStartInstruction(instruction, approvalRequest, approvalTaskName); - - // set some aspect-specific variables - instruction.addProcessVariable(AddRoleVariableNames.FOCUS_NAME, userName); + itemApprovalProcessInterface.prepareStartInstruction(instruction); return instruction; } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/addrole/AddRoleVariableNames.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/ProcessSpecificContent.java similarity index 55% rename from model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/addrole/AddRoleVariableNames.java rename to model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/ProcessSpecificContent.java index 1da9d988223..4a634f0289c 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/processes/addrole/AddRoleVariableNames.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/ProcessSpecificContent.java @@ -1,27 +1,34 @@ -/* - * Copyright (c) 2010-2013 Evolveum - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.evolveum.midpoint.wf.impl.processes.addrole; - -/** - * @author mederly - */ -public class AddRoleVariableNames { - - // Name of focal object to which an assignment is to be made. [String] - public static final String FOCUS_NAME = "FocusName"; - -} +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.tasks; + +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessSpecificStateType; + +import java.util.Map; + +/** + * Process-specific part of WfTaskCreationInstruction. + * + * @author mederly + */ +public interface ProcessSpecificContent { + + void createProcessVariables(Map map, PrismContext prismContext); + + WfProcessSpecificStateType createProcessSpecificState(); +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/ProcessorSpecificContent.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/ProcessorSpecificContent.java new file mode 100644 index 00000000000..eb04b069294 --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/ProcessorSpecificContent.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.tasks; + +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfProcessorSpecificStateType; + +import java.util.Map; + +/** + * Processor-specific part of WfTaskCreationInstruction. + * + * @author mederly + */ +public interface ProcessorSpecificContent { + + WfProcessorSpecificStateType createProcessorSpecificState(); + + void createProcessVariables(Map map, PrismContext prismContext) throws SchemaException; +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/WfProcessInstanceShadowTaskHandler.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfProcessInstanceShadowTaskHandler.java similarity index 90% rename from model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/WfProcessInstanceShadowTaskHandler.java rename to model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfProcessInstanceShadowTaskHandler.java index e4394a0c720..07379dd9901 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/jobs/WfProcessInstanceShadowTaskHandler.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfProcessInstanceShadowTaskHandler.java @@ -14,25 +14,26 @@ * limitations under the License. */ -package com.evolveum.midpoint.wf.impl.jobs; +package com.evolveum.midpoint.wf.impl.tasks; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.*; import com.evolveum.midpoint.task.api.TaskRunResult.TaskRunResultStatus; +import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.LoggingUtils; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.wf.impl.WfConfiguration; import com.evolveum.midpoint.wf.impl.activiti.ActivitiInterface; import com.evolveum.midpoint.wf.impl.messages.QueryProcessCommand; - import org.apache.commons.lang.Validate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.DependsOn; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; - import java.util.List; /** @@ -93,14 +94,12 @@ public TaskRunResult run(Task task) { // is this task already closed? (this flag is set by activiti2midpoint when it gets information about wf process termination) // todo: fixme this is a bit weird if (task.getExecutionStatus() == TaskExecutionStatus.CLOSED) { - LOGGER.info("Task " + task.getName() + " has been flagged as closed; exiting the run() method."); + LOGGER.info("Task {} has been flagged as closed; exiting the run() method.", task); } else { String id = wfTaskUtil.getProcessId(task); if (id != null) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Task " + task.getName() + ": requesting status for wf process id " + id + "..."); - } + LOGGER.debug("Task {}: requesting status for wf process id {}", task, id); queryProcessInstance(id, task, task.getResult()); } } @@ -134,14 +133,14 @@ private void queryProcessInstance(String id, Task task, OperationResult parentRe qpc.setPid(id); try { - activitiInterface.midpoint2activiti(qpc, task, result); - } catch (RuntimeException e) { + activitiInterface.queryActivitiProcessInstance(qpc, task, result); + } catch (RuntimeException|ObjectNotFoundException|ObjectAlreadyExistsException|SchemaException e) { LoggingUtils.logException(LOGGER, "Couldn't send a request to query a process instance to workflow management system", e); result.recordPartialError("Couldn't send a request to query a process instance to workflow management system", e); - } - - result.recordSuccessIfUnknown(); + } finally { + result.computeStatusIfUnknown(); + } } diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTask.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTask.java new file mode 100644 index 00000000000..9b845867854 --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTask.java @@ -0,0 +1,221 @@ +package com.evolveum.midpoint.wf.impl.tasks; + +import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.prism.delta.builder.DeltaBuilder; +import com.evolveum.midpoint.prism.xml.XmlTypeConverter; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskExecutionStatus; +import com.evolveum.midpoint.util.exception.CommunicationException; +import com.evolveum.midpoint.util.exception.ConfigurationException; +import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; +import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; +import com.evolveum.midpoint.wf.util.ApprovalUtils; +import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; +import org.apache.commons.lang3.Validate; + +import javax.xml.datatype.XMLGregorianCalendar; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static com.evolveum.midpoint.task.api.TaskExecutionStatus.WAITING; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_WORKFLOW_CONTEXT; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType.*; + +/** + * A class that describes wf-enabled tasks (plus tasks that do not carry wf process, like "task0" executing changes that do not need approvals) + * + * It points to the activiti process instance information as well as to the corresponding midPoint task. + * + * @author mederly + */ +public class WfTask { + + private WfTaskController wfTaskController; + + private Task task; // must be non-null + private String processInstanceId; // must be non-null for Activiti-related jobs (and may be filled-in later, when activiti process is started) + private ChangeProcessor changeProcessor; // must be non-null + + //region Constructors and basic getters + WfTask(WfTaskController wfTaskController, Task task, ChangeProcessor changeProcessor) { + this(wfTaskController, task, null, changeProcessor); + } + + protected WfTask(WfTaskController wfTaskController, Task task, String processInstanceId, ChangeProcessor changeProcessor) { + Validate.notNull(task, "Task"); + Validate.notNull(changeProcessor, "Change processor"); + this.wfTaskController = wfTaskController; + this.task = task; + this.processInstanceId = processInstanceId; + this.changeProcessor = changeProcessor; + } + + protected WfTask(WfTask original) { + this.wfTaskController = original.wfTaskController; + this.task = original.task; + this.processInstanceId = original.processInstanceId; + this.changeProcessor = original.changeProcessor; + } + + public String getProcessInstanceId() { + return processInstanceId; + } + + public Task getTask() { + return task; + } + + public ChangeProcessor getChangeProcessor() { + return changeProcessor; + } + //endregion + + @Override + public String toString() { + return "WfTask{" + + "task=" + task + + ", processInstanceId='" + processInstanceId + '\'' + + ", changeProcessor=" + changeProcessor + + '}'; + } + + public void addDependent(WfTask wfTask) { + wfTaskController.addDependency(this, wfTask); + } + + public void commitChanges(OperationResult result) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { + task.savePendingModifications(result); + } + + public void resumeTask(OperationResult result) throws SchemaException, ObjectNotFoundException { + wfTaskController.resumeTask(this, result); + } + + public void startWaitingForSubtasks(OperationResult result) throws SchemaException, ObjectNotFoundException { + task.startWaitingForTasksImmediate(result); + } + + public void setWfProcessId(String pid) throws SchemaException { + processInstanceId = pid; + task.addModification( + DeltaBuilder.deltaFor(TaskType.class, getPrismContext()) + .item(F_WORKFLOW_CONTEXT, F_PROCESS_INSTANCE_ID).replace(pid) + .asItemDelta()); + } + + public void setProcessInstanceEndTimestamp() throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { + XMLGregorianCalendar now = XmlTypeConverter.createXMLGregorianCalendar(new Date()); + task.addModification( + DeltaBuilder.deltaFor(TaskType.class, getPrismContext()) + .item(F_WORKFLOW_CONTEXT, F_END_TIMESTAMP).replace(now) + .asItemDelta()); + } + + public TaskExecutionStatus getTaskExecutionStatus() { + return task.getExecutionStatus(); + } + + public void removeCurrentTaskHandlerAndUnpause(OperationResult result) throws SchemaException, ObjectNotFoundException { + boolean wasWaiting = getTaskExecutionStatus() == WAITING; + task.finishHandler(result); + boolean isWaiting = getTaskExecutionStatus() == WAITING; + if (wasWaiting && isWaiting) { // if the task was not closed ... (i.e. if there are other handler(s) on the stack) + wfTaskController.unpauseTask(this, result); + } + } + + public void computeTaskResultIfUnknown(OperationResult result) throws SchemaException, ObjectNotFoundException { + OperationResult taskResult = task.getResult(); + if (result.isUnknown()) { + result.computeStatus(); + } + taskResult.recordStatus(result.getStatus(), result.getMessage(), result.getCause()); + task.setResultImmediate(taskResult, result); + } + + public boolean hasModelContext() { + return getWfTaskUtil().hasModelContext(task); + } + + private WfTaskUtil getWfTaskUtil() { + return wfTaskController.getWfTaskUtil(); + } + + public ModelContext retrieveModelContext(OperationResult result) throws SchemaException, ObjectNotFoundException, CommunicationException, ConfigurationException { + return getWfTaskUtil().getModelContext(task, result); + } + + public List listChildren(OperationResult result) throws SchemaException { + List wfTasks = new ArrayList<>(); + for (Task subtask : task.listSubtasks(result)) { + wfTasks.add(wfTaskController.recreateChildWfTask(subtask, this)); + } + return wfTasks; + } + + public ObjectTreeDeltas retrieveResultingDeltas() throws SchemaException { + return getWfTaskUtil().retrieveResultingDeltas(task); + } + + public void deleteModelOperationContext() throws SchemaException, ObjectNotFoundException { + getWfTaskUtil().deleteModelOperationContext(task); + } + + public void storeModelContext(ModelContext modelContext) throws SchemaException { + getWfTaskUtil().storeModelContext(task, modelContext); + } + + public List listDependents(OperationResult result) throws SchemaException, ObjectNotFoundException { + List wfTasks = new ArrayList<>(); + for (Task subtask : task.listDependents(result)) { + wfTasks.add(wfTaskController.recreateWfTask(subtask)); + } + return wfTasks; + } + + public WfTask getParentJob(OperationResult result) throws SchemaException, ObjectNotFoundException { + Task parentTask = task.getParentTask(result); + return wfTaskController.recreateWfTask(parentTask); + } + + void setProcessInstanceState(String stateDescription) throws SchemaException { + task.addModification(DeltaBuilder.deltaFor(TaskType.class, getPrismContext()).item(F_WORKFLOW_CONTEXT, F_STATE).replace(stateDescription).asItemDelta()); + } + + private PrismContext getPrismContext() { + return wfTaskController.getPrismContext(); + } + + public String getProcessInstanceName() { + return task.getWorkflowContext() != null ? task.getWorkflowContext().getProcessInstanceName() : null; + } + + public String getAnswer() { + return task.getWorkflowContext() != null ? task.getWorkflowContext().getAnswer() : null; + } + + @SuppressWarnings("unchecked") + public PrismObject getRequesterIfExists(OperationResult result) { + if (task.getWorkflowContext() == null || task.getWorkflowContext().getRequesterRef() == null) { + return null; + } + ObjectReferenceType requesterRef = task.getWorkflowContext().getRequesterRef(); + return (PrismObject) wfTaskController.getMiscDataUtil().resolveAndStoreObjectReference(requesterRef, result); + } + + public void setAnswer(String answer) throws SchemaException { + task.addModifications(DeltaBuilder.deltaFor(TaskType.class, getPrismContext()) + .item(F_WORKFLOW_CONTEXT, F_ANSWER).replace(answer) + .item(F_WORKFLOW_CONTEXT, F_APPROVED).replace(ApprovalUtils.approvalBooleanValue(answer)) + .asItemDeltas()); + } +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskController.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskController.java new file mode 100644 index 00000000000..ce036479bc5 --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskController.java @@ -0,0 +1,413 @@ +/* + * Copyright (c) 2010-2013 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.tasks; + +import com.evolveum.midpoint.audit.api.AuditEventRecord; +import com.evolveum.midpoint.audit.api.AuditEventStage; +import com.evolveum.midpoint.audit.api.AuditService; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskManager; +import com.evolveum.midpoint.util.exception.ObjectAlreadyExistsException; +import com.evolveum.midpoint.util.exception.ObjectNotFoundException; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.exception.SystemException; +import com.evolveum.midpoint.util.logging.LoggingUtils; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.wf.api.ProcessListener; +import com.evolveum.midpoint.wf.api.WorkItemListener; +import com.evolveum.midpoint.wf.api.WorkflowException; +import com.evolveum.midpoint.wf.impl.WfConfiguration; +import com.evolveum.midpoint.wf.impl.activiti.ActivitiInterface; +import com.evolveum.midpoint.wf.impl.messages.*; +import com.evolveum.midpoint.wf.impl.processes.ProcessInterfaceFinder; +import com.evolveum.midpoint.wf.impl.processes.ProcessMidPointInterface; +import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; +import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; +import com.evolveum.midpoint.wf.impl.processors.primary.PcpWfTask; +import com.evolveum.midpoint.wf.impl.processors.primary.PrimaryChangeProcessor; +import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; +import org.apache.commons.lang.Validate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static com.evolveum.midpoint.task.api.TaskExecutionStatus.WAITING; + +/** + * Manages everything related to a activiti process instance, including the task that monitors that process instance. + * + * This class provides a facade over ugly mess of code managing activiti + task pair describing a workflow process instance. + * + * @author mederly + */ +@Component +public class WfTaskController { + + private static final Trace LOGGER = TraceManager.getTrace(WfTaskController.class); + + public static final long TASK_START_DELAY = 5000L; + private static final Object DOT_CLASS = WfTaskController.class.getName() + "."; + + private Set processListeners = new HashSet<>(); + private Set workItemListeners = new HashSet<>(); + + //region Spring beans + @Autowired + private WfTaskUtil wfTaskUtil; + + @Autowired + private TaskManager taskManager; + + @Autowired + private ActivitiInterface activitiInterface; + + @Autowired + private AuditService auditService; + + @Autowired + private MiscDataUtil miscDataUtil; + + @Autowired + private ProcessInterfaceFinder processInterfaceFinder; + + @Autowired + private WfConfiguration wfConfiguration; + + @Autowired + private PrismContext prismContext; + //endregion + + //region Job creation & re-creation + /** + * Creates a background task, just as prescribed by the task creation instruction. + * + * @param instruction the job creation instruction + * @param parentWfTask the job that will be the parent of newly created one; it may be null + */ + + public WfTask submitWfTask(WfTaskCreationInstruction instruction, WfTask parentWfTask, OperationResult result) throws SchemaException, ObjectNotFoundException { + return submitWfTask(instruction, parentWfTask.getTask(), result); + } + + /** + * As before, but this time we know only the parent task (not a job). + * + * @param instruction the job creation instruction + * @param parentTask the task that will be the parent of the task of newly created job; it may be null + */ + public WfTask submitWfTask(WfTaskCreationInstruction instruction, Task parentTask, OperationResult result) throws SchemaException, ObjectNotFoundException { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Processing start instruction:\n{}", instruction.debugDump()); + } + Task task = submitTask(instruction, parentTask, result); + WfTask wfTask = recreateWfTask(task, instruction.getChangeProcessor()); + if (!instruction.isNoProcess()) { + startWorkflowProcessInstance(wfTask, instruction, result); + } + return wfTask; + } + + /** + * Re-creates a job, based on existing task information. + * + * @param task a task from task-processInstance pair + * @return recreated job + */ + public WfTask recreateWfTask(Task task) { + return recreateWfTask(task, wfTaskUtil.getChangeProcessor(task)); + } + + public WfTask recreateWfTask(Task task, ChangeProcessor changeProcessor) { + String processInstanceId = wfTaskUtil.getProcessId(task); + if (changeProcessor instanceof PrimaryChangeProcessor) { + return new PcpWfTask(this, task, processInstanceId, changeProcessor); + } else { + return new WfTask(this, task, processInstanceId, changeProcessor); + } + } + + /** + * Re-creates a child job, knowing the task and the parent job. + * + * @param subtask a task from task-processInstance pair + * @param parentWfTask the parent job + * @return recreated job + */ + public WfTask recreateChildWfTask(Task subtask, WfTask parentWfTask) { + return new WfTask(this, subtask, wfTaskUtil.getProcessId(subtask), parentWfTask.getChangeProcessor()); + } + + /** + * Re-creates a root job, based on existing task information. Does not try to find the wf process instance. + */ + public WfTask recreateRootWfTask(Task task) { + return new WfTask(this, task, wfTaskUtil.getChangeProcessor(task)); + } + //endregion + + //region Working with midPoint tasks + + private Task submitTask(WfTaskCreationInstruction instruction, Task parentTask, OperationResult result) throws SchemaException, ObjectNotFoundException { + Task wfTask = instruction.createTask(this, parentTask); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Switching workflow root or child task to background:\n{}", wfTask.debugDump()); + } + taskManager.switchToBackground(wfTask, result); + return wfTask; + } + + /** + * Beware, in order to make the change permanent, it is necessary to call commitChanges on + * "executesFirst". It is advisable not to modify underlying tasks between 'addDependency' + * and 'commitChanges' because of the savePendingModifications() mechanism that is used here. + * + * @param executesFirst + * @param executesSecond + */ + public void addDependency(WfTask executesFirst, WfTask executesSecond) { + Validate.notNull(executesFirst.getTask()); + Validate.notNull(executesSecond.getTask()); + LOGGER.trace("Setting dependency of {} on 'task0' {}", executesSecond, executesFirst); + executesFirst.getTask().addDependent(executesSecond.getTask().getTaskIdentifier()); + } + + public void resumeTask(WfTask wfTask, OperationResult result) throws SchemaException, ObjectNotFoundException { + taskManager.resumeTask(wfTask.getTask(), result); + } + + public void unpauseTask(WfTask wfTask, OperationResult result) throws SchemaException, ObjectNotFoundException { + taskManager.unpauseTask(wfTask.getTask(), result); + } + //endregion + + //region Working with Activiti process instances + + private void startWorkflowProcessInstance(WfTask wfTask, WfTaskCreationInstruction instruction, OperationResult parentResult) { + OperationResult result = parentResult.createSubresult(DOT_CLASS + "startWorkflowProcessInstance"); + try { + LOGGER.trace("startWorkflowProcessInstance starting; instruction = {}", instruction); + Task task = wfTask.getTask(); + + StartProcessCommand spc = new StartProcessCommand(); + spc.setProcessName(instruction.getProcessName()); + spc.setProcessInstanceName(instruction.getProcessInstanceName()); + spc.setSendStartConfirmation(instruction.isSendStartConfirmation()); + spc.setVariablesFrom(instruction.getAllProcessVariables()); + spc.addVariable(CommonProcessVariableNames.VARIABLE_MIDPOINT_TASK_OID, task.getOid()); + spc.setProcessOwner(task.getOwner().getOid()); + + activitiInterface.startActivitiProcessInstance(spc, task, result); + auditProcessStart(wfTask, spc.getVariables(), result); + notifyProcessStart(wfTask, result); + } catch (SchemaException|RuntimeException|ObjectNotFoundException|ObjectAlreadyExistsException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't send a request to start a process instance to workflow management system", e); + try { + wfTask.setProcessInstanceState("Workflow process instance creation could not be requested: " + e); + } catch (SchemaException e1) { + throw new SystemException(e1); // never occurs + } + result.recordFatalError("Couldn't send a request to start a process instance to workflow management system: " + e.getMessage(), e); + throw new SystemException("Workflow process instance creation could not be requested", e); + } finally { + result.computeStatusIfUnknown(); + } + LOGGER.trace("startWorkflowProcessInstance finished"); + } + + public void onProcessEvent(ProcessEvent event, Task task, OperationResult result) + throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { + WfTask wfTask = recreateWfTask(task); + + LOGGER.trace("Updating instance state and activiti process instance ID in task {}", task); + + if (wfTask.getProcessInstanceId() == null) { + wfTask.setWfProcessId(event.getPid()); + } + + // update state description + ProcessMidPointInterface pmi = processInterfaceFinder.getProcessInterface(event.getVariables()); + String stateDescription = pmi.getState(event.getVariables()); + if (stateDescription == null || stateDescription.isEmpty()) { + if (event instanceof ProcessStartedEvent) { + stateDescription = "Workflow process instance has been created (process id " + event.getPid() + ")"; + } else if (event instanceof ProcessFinishedEvent) { + stateDescription = "Workflow process instance has ended (process id " + event.getPid() + ")"; + } else { + stateDescription = "Workflow process instance has proceeded further (process id " + event.getPid() + ")"; + } + } + wfTask.setProcessInstanceState(stateDescription); + + wfTask.commitChanges(result); + + if (event instanceof ProcessFinishedEvent || !event.isRunning()) { + onProcessFinishedEvent(event, wfTask, result); + } + } + + private void onProcessFinishedEvent(ProcessEvent event, WfTask wfTask, OperationResult result) + throws ObjectAlreadyExistsException, ObjectNotFoundException, SchemaException { + LOGGER.trace("onProcessFinishedEvent starting"); + LOGGER.trace("Calling onProcessEnd on {}", wfTask.getChangeProcessor()); + wfTask.getChangeProcessor().onProcessEnd(event, wfTask, result); + wfTask.setProcessInstanceEndTimestamp(); + wfTask.setAnswer(event.getAnswer()); // TODO or should we do this on each process event? + wfTask.commitChanges(result); + + auditProcessEnd(wfTask, event, result); + notifyProcessEnd(wfTask, result); + + // passive tasks can be 'let go' at this point + if (wfTask.getTaskExecutionStatus() == WAITING) { + wfTask.computeTaskResultIfUnknown(result); + wfTask.removeCurrentTaskHandlerAndUnpause(result); // removes WfProcessInstanceShadowTaskHandler + } + LOGGER.trace("onProcessFinishedEvent done"); + } + + private ChangeProcessor getChangeProcessor(Map variables) { + String cpName = (String) variables.get(CommonProcessVariableNames.VARIABLE_CHANGE_PROCESSOR); + Validate.notNull(cpName, "Change processor is not defined among process instance variables"); + return wfConfiguration.findChangeProcessor(cpName); + } + + private ChangeProcessor getChangeProcessor(TaskEvent taskEvent) { + return getChangeProcessor(taskEvent.getVariables()); + } + + //endregion + + //region Processing work item (task) events + + // workItem contains taskRef, assignee, candidates resolved (if possible) + @SuppressWarnings("unchecked") + public void onTaskEvent(WorkItemType workItem, TaskEvent taskEvent, OperationResult result) throws WorkflowException, SchemaException { + + final TaskType shadowTaskType = (TaskType) ObjectTypeUtil.getObjectFromReference(workItem.getTaskRef()); + if (shadowTaskType == null) { + LOGGER.warn("No task in workItem " + workItem + ", audit and notifications couldn't be performed."); + return; + } + final Task shadowTask = taskManager.createTaskInstance(shadowTaskType.asPrismObject(), result); + final WfTask wfTask = recreateWfTask(shadowTask); + + // auditing & notifications + if (taskEvent instanceof TaskCreatedEvent) { + auditWorkItemEvent(workItem, wfTask, taskEvent, AuditEventStage.REQUEST, result); + try { + notifyWorkItemCreated(workItem, wfTask, result); + } catch (SchemaException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't send notification about work item create event", e); + } + } else if (taskEvent instanceof TaskCompletedEvent) { + auditWorkItemEvent(workItem, wfTask, taskEvent, AuditEventStage.EXECUTION, result); + try { + notifyWorkItemCompleted(workItem, wfTask, result); + } catch (SchemaException e) { + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't audit work item complete event", e); + } + } + } + //endregion + + //region Auditing and notifications + private void auditProcessStart(WfTask wfTask, Map variables, OperationResult result) { + auditProcessStartEnd(wfTask, AuditEventStage.REQUEST, variables, result); + } + + private void auditProcessEnd(WfTask wfTask, ProcessEvent event, OperationResult result) { + auditProcessStartEnd(wfTask, AuditEventStage.EXECUTION, event.getVariables(), result); + } + + private void auditProcessStartEnd(WfTask wfTask, AuditEventStage stage, Map variables, OperationResult result) { + AuditEventRecord auditEventRecord = wfTask.getChangeProcessor().prepareProcessInstanceAuditRecord(wfTask, stage, variables, result); + auditService.audit(auditEventRecord, wfTask.getTask()); + } + + private void notifyProcessStart(WfTask wfTask, OperationResult result) throws SchemaException { + for (ProcessListener processListener : processListeners) { + processListener.onProcessInstanceStart(wfTask.getTask(), result); + } + } + + private void notifyProcessEnd(WfTask wfTask, OperationResult result) throws SchemaException { + for (ProcessListener processListener : processListeners) { + processListener.onProcessInstanceEnd(wfTask.getTask(), result); + } + } + + private void notifyWorkItemCreated(WorkItemType workItem, WfTask wfTask, OperationResult result) throws SchemaException { + for (WorkItemListener workItemListener : workItemListeners) { + workItemListener.onWorkItemCreation(workItem, wfTask.getTask(), result); + } + } + + private void notifyWorkItemCompleted(WorkItemType workItem, WfTask wfTask, OperationResult result) throws SchemaException { + for (WorkItemListener workItemListener : workItemListeners) { + workItemListener.onWorkItemCompletion(workItem, wfTask.getTask(), result); + } + } + + // workItem contains taskRef, assignee, candidates resolved (if possible) + private void auditWorkItemEvent(WorkItemType workItem, WfTask wfTask, TaskEvent taskEvent, AuditEventStage stage, OperationResult result) throws WorkflowException { + AuditEventRecord auditEventRecord = getChangeProcessor(taskEvent).prepareWorkItemAuditRecord(workItem, wfTask, taskEvent, stage, result); + auditService.audit(auditEventRecord, wfTask.getTask()); + } + + public void registerProcessListener(ProcessListener processListener) { + LOGGER.trace("Registering process listener {}", processListener); + processListeners.add(processListener); + } + + public void registerWorkItemListener(WorkItemListener workItemListener) { + LOGGER.trace("Registering work item listener {}", workItemListener); + workItemListeners.add(workItemListener); + } + //endregion + + //region Getters and setters + public WfTaskUtil getWfTaskUtil() { + return wfTaskUtil; + } + + public MiscDataUtil getMiscDataUtil() { + return miscDataUtil; + } + + public PrismContext getPrismContext() { + return prismContext; + } + + public TaskManager getTaskManager() { + return taskManager; + } + + public WfConfiguration getWfConfiguration() { + return wfConfiguration; + } + + //endregion +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskCreationInstruction.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskCreationInstruction.java new file mode 100644 index 00000000000..9d4e4f949da --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskCreationInstruction.java @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2010-2013 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.tasks; + +import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.impl.controller.ModelOperationTaskHandler; +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.prism.PrismContext; +import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.task.api.*; +import com.evolveum.midpoint.util.DebugDumpable; +import com.evolveum.midpoint.util.DebugUtil; +import com.evolveum.midpoint.util.MiscUtil; +import com.evolveum.midpoint.util.exception.SchemaException; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.wf.impl.processes.ProcessMidPointInterface; +import com.evolveum.midpoint.wf.impl.processes.common.ActivitiUtil; +import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRef; +import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRefImpl; +import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; +import com.evolveum.midpoint.wf.impl.util.MiscDataUtil; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import com.evolveum.prism.xml.ns._public.types_3.PolyStringType; +import org.apache.commons.lang.Validate; + +import java.util.*; + +import static com.evolveum.midpoint.prism.xml.XmlTypeConverter.createXMLGregorianCalendar; +import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.createObjectRef; +import static com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames.*; + +/** + * A generic instruction to start a background task; with or without a workflow process instance. + * May be subclassed in order to add further functionality. + * + * @author mederly + */ +public class WfTaskCreationInstruction implements DebugDumpable { + + private static final Trace LOGGER = TraceManager.getTrace(WfTaskCreationInstruction.class); + + private final ChangeProcessor changeProcessor; + + private final WfContextType wfContext = new WfContextType(); // workflow context to be put into the task + private ModelContext taskModelContext; // model context to be put into the task + + private final Date processCreationTimestamp = new Date(); + + protected final PRC processorContent; + private final PCS processContent; + + private PrismObject taskObject; // object to be attached to the task; this object must have its definition available + private PrismObject taskOwner; // if null, owner from parent task will be taken (if there's no parent task, exception will be thrown) + private PolyStringType taskName; // name of task to be created/updated (applies only if the task has no name already) - e.g. "Approve adding role R to U" + + private boolean executeModelOperationHandler; // should the task contain model operation to be executed? + private boolean noProcess; // should the task provide no wf process (only direct execution of model operation)? + + private boolean simple; // is workflow process simple? (i.e. such that requires periodic watching of its state) + private boolean sendStartConfirmation = true; // should we send explicit "process started" event when the process was started by midPoint? + // for listener-enabled processes this can be misleading, because "process started" event could come + // after "process finished" one (for immediately-finishing processes) + // + // unfortunately, it seems we have to live with this (unless we define a "process started" listener) + + private TaskExecutionStatus taskInitialState = TaskExecutionStatus.RUNNABLE; + + // what should be executed at a given occasion (in the order of being in this list) + private final List handlersAfterModelOperation = new ArrayList<>(); + private final List handlersBeforeModelOperation = new ArrayList<>(); + private final List handlersAfterWfProcess = new ArrayList<>(); + + //region Constructors + protected WfTaskCreationInstruction(ChangeProcessor changeProcessor, PRC processorContent, PCS processContent) { + Validate.notNull(changeProcessor); + this.changeProcessor = changeProcessor; + this.processorContent = processorContent; + this.processContent = processContent; + } + + @SuppressWarnings("unchecked") + public static WfTaskCreationInstruction createModelOnly(ChangeProcessor changeProcessor, ModelContext modelContext) throws SchemaException { + WfTaskCreationInstruction instruction = new WfTaskCreationInstruction(changeProcessor, null, null); + instruction.setNoProcess(true); + instruction.setTaskModelContext(modelContext); + instruction.setExecuteModelOperationHandler(true); + return instruction; + } + + @SuppressWarnings("unchecked") + public static WfTaskCreationInstruction createWfOnly(ChangeProcessor changeProcessor, + ProcessorSpecificContent processorSpecificContent, ProcessSpecificContent processSpecificContent) { + return new WfTaskCreationInstruction(changeProcessor, processorSpecificContent, processSpecificContent); + } + + @SuppressWarnings("unchecked") + public static WfTaskCreationInstruction createEmpty(ChangeProcessor changeProcessor) throws SchemaException { + WfTaskCreationInstruction instruction = new WfTaskCreationInstruction(changeProcessor, null, null); + instruction.setNoProcess(true); + return instruction; + } + //endregion + + // region Getters and setters + public ChangeProcessor getChangeProcessor() { + return changeProcessor; + } + + protected PrismContext getPrismContext() { return changeProcessor.getPrismContext(); } + + public void setSimple(boolean simple) { + this.simple = simple; + } + + public boolean isSendStartConfirmation() { + return sendStartConfirmation; + } + + public void setSendStartConfirmation(boolean sendStartConfirmation) { + this.sendStartConfirmation = sendStartConfirmation; + } + + public String getProcessName() { + return wfContext.getProcessName(); + } + + public void setProcessName(String name) { + wfContext.setProcessName(name); + } + + public String getProcessInstanceName() { + return wfContext.getProcessInstanceName(); + } + + public void setProcessInstanceName(String name) { + wfContext.setProcessInstanceName(name); + } + + public void setTaskName(String taskName) { + this.taskName = new PolyStringType(taskName); + } + + public boolean isNoProcess() { + return noProcess; + } + + public boolean startsWorkflowProcess() { + return !noProcess; + } + + public void setNoProcess(boolean noProcess) { + this.noProcess = noProcess; + } + + public void setCreateTaskAsSuspended() { + this.taskInitialState = TaskExecutionStatus.SUSPENDED; + } + + public void setCreateTaskAsWaiting() { + this.taskInitialState = TaskExecutionStatus.WAITING; + } + + public List getHandlersAfterModelOperation() { + return handlersAfterModelOperation; + } + + public List getHandlersBeforeModelOperation() { + return handlersBeforeModelOperation; + } + + public List getHandlersAfterWfProcess() { + return handlersAfterWfProcess; + } + + public void setHandlersBeforeModelOperation(String... handlerUri) { + setHandlers(handlersBeforeModelOperation, createUriStackEntries(handlerUri)); + } + + public void setHandlersAfterModelOperation(String... handlerUri) { + setHandlers(handlersAfterModelOperation, createUriStackEntries(handlerUri)); + } + + public void addHandlersAfterWfProcessAtEnd(String... handlerUriArray) { + addHandlersAtEnd(handlersAfterWfProcess, createUriStackEntries(handlerUriArray)); + } + + private List createUriStackEntries(String[] handlerUriArray) { + List retval = new ArrayList<>(); + for (String handlerUri : handlerUriArray) { + retval.add(createUriStackEntry(handlerUri)); + } + return retval; + } + + private UriStackEntry createUriStackEntry(String handlerUri, TaskRecurrence recurrence, ScheduleType scheduleType, TaskBinding taskBinding) { + UriStackEntry uriStackEntry = new UriStackEntry(); + uriStackEntry.setHandlerUri(handlerUri); + uriStackEntry.setRecurrence(recurrence != null ? recurrence.toTaskType() : null); + uriStackEntry.setSchedule(scheduleType); + uriStackEntry.setBinding(taskBinding != null ? taskBinding.toTaskType() : null); + return uriStackEntry; + } + + private UriStackEntry createUriStackEntry(String handlerUri) { + return createUriStackEntry(handlerUri, TaskRecurrence.SINGLE, new ScheduleType(), null); + } + + private void setHandlers(List list, List uriStackEntry) { + list.clear(); + list.addAll(uriStackEntry); + } + + private void addHandlersAtEnd(List list, List uriStackEntry) { + list.addAll(uriStackEntry); + } + + public void setExecuteModelOperationHandler(boolean executeModelOperationHandler) { + this.executeModelOperationHandler = executeModelOperationHandler; + } + + public void setTaskObject(PrismObject taskObject) { + this.taskObject = taskObject; + } + + public void setTaskOwner(PrismObject taskOwner) { + this.taskOwner = taskOwner; + } + + public void setTaskModelContext(ModelContext taskModelContext) { + this.taskModelContext = taskModelContext; + } + + public void setObjectRef(ObjectReferenceType ref, OperationResult result) { + ref = getChangeProcessor().getWorkflowManager().getMiscDataUtil().resolveObjectReferenceName(ref, result); + wfContext.setObjectRef(ref); + } + + public void setObjectRef(ModelContext modelContext, OperationResult result) { + ObjectType focus = MiscDataUtil.getFocusObjectNewOrOld(modelContext); + setObjectRef(ObjectTypeUtil.createObjectRef(focus), result); + } + + public void setTargetRef(ObjectReferenceType ref, OperationResult result) { + ref = getChangeProcessor().getWorkflowManager().getMiscDataUtil().resolveObjectReferenceName(ref, result); + wfContext.setTargetRef(ref); + } + + public void setRequesterRef(PrismObject requester) { + wfContext.setRequesterRef(createObjectRef(requester)); + } + + public void setProcessInterfaceBean(ProcessMidPointInterface processInterfaceBean) { + wfContext.setProcessInterface(processInterfaceBean.getBeanName()); + } + //endregion + + //region Diagnostics + public String toString() { + return "WfTaskCreationInstruction: processDefinitionKey = " + getProcessName() + ", simple: " + simple; + } + + @Override + public String debugDump() { + return debugDump(0); + } + + @Override + public String debugDump(int indent) { + StringBuilder sb = new StringBuilder(); + + DebugUtil.indentDebugDump(sb, indent); + sb.append("WfTaskCreationInstruction: process: ").append(getProcessName()).append("/").append(getProcessInstanceName()); + sb.append(" ").append(simple ? "simple" : "smart").append(", ").append(noProcess ? "no-process" : "with-process").append(", model-context: "); + sb.append(taskModelContext != null ? "YES" : "no").append(", task = ").append(taskName).append("\n"); + + DebugUtil.indentDebugDump(sb, indent); + sb.append("Workflow context:\n"); + sb.append(wfContext.asPrismContainerValue().debugDump(indent+2)); + + DebugUtil.debugDumpWithLabel(sb, "Change processor", changeProcessor.getClass().getName(), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Process creation timestamp", String.valueOf(processCreationTimestamp), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Task object", String.valueOf(taskObject), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Task owner", String.valueOf(taskOwner), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Task initial state", String.valueOf(taskInitialState), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Send start confirmation", String.valueOf(sendStartConfirmation), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Handlers after model operation", String.valueOf(handlersAfterModelOperation), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Handlers before model operation", String.valueOf(handlersBeforeModelOperation), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Handlers after wf process", String.valueOf(handlersAfterWfProcess), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Processor instruction", String.valueOf(processorContent), indent+1); + DebugUtil.debugDumpWithLabel(sb, "Process instruction", String.valueOf(processContent), indent+1); + + return sb.toString(); + + } + //endregion + + //region "Output" methods + public Task createTask(WfTaskController taskController, Task parentTask) throws SchemaException { + + LOGGER.trace("createTask starting; parent task = {}", parentTask); + + final WfTaskUtil wfTaskUtil = taskController.getWfTaskUtil(); + + final Task task; + if (parentTask != null) { + task = parentTask.createSubtask(); + } else { + task = taskController.getTaskManager().createTaskInstance(); + if (taskOwner == null) { + throw new IllegalStateException("No task owner for " + task); + } + task.setOwner(taskOwner); + } + + task.setInitialExecutionStatus(taskInitialState); + task.setCategory(TaskCategory.WORKFLOW); + + if (taskObject != null) { + task.setObjectRef(taskObject.getOid(), taskObject.getDefinition().getTypeName()); + } else if (parentTask != null && parentTask.getObjectRef() != null) { + task.setObjectRef(parentTask.getObjectRef()); + } + if (task.getName() == null || task.getName().toPolyString().isEmpty()) { + task.setName(taskName); + } + + // push the handlers, beginning with these that should execute last + wfTaskUtil.pushHandlers(task, getHandlersAfterModelOperation()); + if (executeModelOperationHandler) { + task.pushHandlerUri(ModelOperationTaskHandler.MODEL_OPERATION_TASK_URI, null, null); + } + wfTaskUtil.pushHandlers(task, getHandlersBeforeModelOperation()); + wfTaskUtil.pushHandlers(task, getHandlersAfterWfProcess()); + if (!noProcess) { + if (simple) { + ScheduleType schedule = new ScheduleType(); + schedule.setInterval(taskController.getWfConfiguration().getProcessCheckInterval()); + schedule.setEarliestStartTime(MiscUtil.asXMLGregorianCalendar(new Date(System.currentTimeMillis() + WfTaskController.TASK_START_DELAY))); + task.pushHandlerUri(WfProcessInstanceShadowTaskHandler.HANDLER_URI, schedule, TaskBinding.LOOSE); + } else { + task.pushHandlerUri(WfProcessInstanceShadowTaskHandler.HANDLER_URI, new ScheduleType(), null); // note that this handler will not be actively used (at least for now) + task.makeWaiting(); + } + } + + // model and workflow context + if (taskModelContext != null) { + task.setModelOperationContext(((LensContext) taskModelContext).toLensContextType()); + } + wfContext.setChangeProcessor(changeProcessor.getClass().getName()); + wfContext.setStartTimestamp(createXMLGregorianCalendar(processCreationTimestamp)); + if (processorContent != null) { + wfContext.setProcessorSpecificState(processorContent.createProcessorSpecificState()); + } + if (processContent != null) { + wfContext.setProcessSpecificState(processContent.createProcessSpecificState()); + } + task.setWorkflowContext(wfContext); + + return task; + } + + public Map getAllProcessVariables() throws SchemaException { + Map map = new HashMap<>(); + map.put(VARIABLE_PROCESS_INSTANCE_NAME, wfContext.getProcessInstanceName()); + map.put(VARIABLE_START_TIME, processCreationTimestamp); + map.put(VARIABLE_OBJECT_REF, toLightweightObjectRef(wfContext.getObjectRef())); + map.put(VARIABLE_TARGET_REF, toLightweightObjectRef(wfContext.getTargetRef())); + map.put(VARIABLE_REQUESTER_REF, toLightweightObjectRef(wfContext.getRequesterRef())); + map.put(VARIABLE_CHANGE_PROCESSOR, changeProcessor.getClass().getName()); + map.put(VARIABLE_PROCESS_INTERFACE_BEAN_NAME, wfContext.getProcessInterface()); + map.put(VARIABLE_UTIL, new ActivitiUtil()); + if (processorContent != null) { + processorContent.createProcessVariables(map, getPrismContext()); + } + if (processContent != null) { + processContent.createProcessVariables(map, getPrismContext()); + } + return map; + } + + private LightweightObjectRef toLightweightObjectRef(ObjectReferenceType ref) { + return ref != null ? new LightweightObjectRefImpl(ref) : null; + } + + //endregion +} \ No newline at end of file diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskUtil.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskUtil.java new file mode 100644 index 00000000000..83cb0d47651 --- /dev/null +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/tasks/WfTaskUtil.java @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2010-2016 Evolveum + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.evolveum.midpoint.wf.impl.tasks; + +import com.evolveum.midpoint.model.api.context.ModelContext; +import com.evolveum.midpoint.model.impl.lens.LensContext; +import com.evolveum.midpoint.prism.*; +import com.evolveum.midpoint.prism.delta.ItemDelta; +import com.evolveum.midpoint.prism.delta.builder.DeltaBuilder; +import com.evolveum.midpoint.prism.path.ItemPath; +import com.evolveum.midpoint.provisioning.api.ProvisioningService; +import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.task.api.Task; +import com.evolveum.midpoint.task.api.TaskBinding; +import com.evolveum.midpoint.util.exception.*; +import com.evolveum.midpoint.util.logging.Trace; +import com.evolveum.midpoint.util.logging.TraceManager; +import com.evolveum.midpoint.wf.impl.WfConfiguration; +import com.evolveum.midpoint.wf.impl.processors.ChangeProcessor; +import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; +import com.evolveum.midpoint.wf.impl.processors.primary.aspect.PrimaryChangeAspect; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +import static com.evolveum.midpoint.prism.util.CloneUtil.cloneListMembers; +import static com.evolveum.midpoint.schema.constants.ObjectTypes.TASK; +import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.createObjectRef; +import static com.evolveum.midpoint.schema.util.ObjectTypeUtil.objectReferenceListToPrismReferenceValues; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_WORKFLOW_CONTEXT; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType.*; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WfPrimaryChangeProcessorStateType.F_DELTAS_TO_PROCESS; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.WfPrimaryChangeProcessorStateType.F_RESULTING_DELTAS; + +/** + * Handles low-level task operations. + * + * @author mederly + */ + +@Component +public class WfTaskUtil { + + @Autowired + private WfConfiguration wfConfiguration; + + @Autowired + private PrismContext prismContext; + + @Autowired + private ProvisioningService provisioningService; + + private static final Trace LOGGER = TraceManager.getTrace(WfTaskUtil.class); + + public static final String WAIT_FOR_TASKS_HANDLER_URI = "<<< marker for calling pushWaitForTasksHandlerUri >>>"; + + public static WfContextType getWorkflowContextChecked(Task task) { + if (task == null) { + throw new IllegalStateException("No task"); + } else if (task.getWorkflowContext() == null) { + throw new IllegalStateException("No workflow context in " + task); + } else { + return task.getWorkflowContext(); + } + } + + @NotNull + public PrimaryChangeAspect getPrimaryChangeAspect(Task task, Collection aspects) { + WfContextType wfc = getWorkflowContextChecked(task); + WfProcessorSpecificStateType pss = wfc.getProcessorSpecificState(); + if (!(pss instanceof WfPrimaryChangeProcessorStateType)) { + throw new IllegalStateException("Expected " + WfPrimaryChangeProcessorStateType.class + " but got " + pss + " in task " + task); + } + WfPrimaryChangeProcessorStateType pcps = ((WfPrimaryChangeProcessorStateType) pss); + String aspectClassName = pcps.getChangeAspect(); + if (aspectClassName == null) { + throw new IllegalStateException("No wf primary change aspect defined in task " + task); + } + for (PrimaryChangeAspect a : aspects) { + if (aspectClassName.equals(a.getClass().getName())) { + return a; + } + } + throw new IllegalStateException("Primary change aspect " + aspectClassName + " is not registered."); + } + + @NotNull + public ChangeProcessor getChangeProcessor(Task task) { + String processorClassName = task.getWorkflowContext() != null ? task.getWorkflowContext().getChangeProcessor() : null; + if (processorClassName == null) { + throw new IllegalStateException("No change processor defined in task " + task); + } + return wfConfiguration.findChangeProcessor(processorClassName); + } + + public String getProcessId(Task task) { + if (task.getWorkflowContext() != null) { + return task.getWorkflowContext().getProcessInstanceId(); + } else { + return null; + } + } + + public boolean hasModelContext(Task task) { + return task.getModelOperationContext() != null; + } + + public ModelContext getModelContext(Task task, OperationResult result) throws SchemaException, ConfigurationException, ObjectNotFoundException, CommunicationException { + LensContextType modelContextType = task.getModelOperationContext(); + if (modelContextType == null) { + return null; + } + return LensContext.fromLensContextType(modelContextType, prismContext, provisioningService, result); + } + + public void storeModelContext(Task task, ModelContext context) throws SchemaException { + LensContextType modelContext = context != null ? ((LensContext) context).toLensContextType() : null; + storeModelContext(task, modelContext); + } + + public void storeModelContext(Task task, LensContextType context) throws SchemaException { + task.setModelOperationContext(context); + } + + public void storeResultingDeltas(ObjectTreeDeltas deltas, Task task) throws SchemaException { + ObjectTreeDeltasType deltasType = ObjectTreeDeltas.toObjectTreeDeltasType(deltas); + if (task.getWorkflowContext().getProcessorSpecificState() == null) { + throw new IllegalStateException("No processor specific state in task " + task); + } + ItemDefinition def = prismContext.getSchemaRegistry() + .findContainerDefinitionByCompileTimeClass(WfPrimaryChangeProcessorStateType.class) + .findPropertyDefinition(F_RESULTING_DELTAS); + ItemPath path = new ItemPath(F_WORKFLOW_CONTEXT, F_PROCESSOR_SPECIFIC_STATE, F_RESULTING_DELTAS); + task.addModification(DeltaBuilder.deltaFor(TaskType.class, prismContext) + .item(path, def).replace(deltasType) + .asItemDelta()); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Stored deltas into task {}:\n{}", task, deltas); // TODO debug dump + } + } + + public ObjectTreeDeltas retrieveDeltasToProcess(Task task) throws SchemaException { + PrismProperty deltaTypePrismProperty = task.getTaskPrismObject().findProperty(new ItemPath(F_WORKFLOW_CONTEXT, F_PROCESSOR_SPECIFIC_STATE, F_DELTAS_TO_PROCESS)); + if (deltaTypePrismProperty == null) { + throw new SchemaException("No deltas to process in task extension; task = " + task); + } + return ObjectTreeDeltas.fromObjectTreeDeltasType(deltaTypePrismProperty.getRealValue(), prismContext); + } + + public ObjectTreeDeltas retrieveResultingDeltas(Task task) throws SchemaException { + PrismProperty deltaTypePrismProperty = task.getTaskPrismObject().findProperty(new ItemPath(F_WORKFLOW_CONTEXT, F_PROCESSOR_SPECIFIC_STATE, F_RESULTING_DELTAS)); + if (deltaTypePrismProperty == null) { + return null; + } + return ObjectTreeDeltas.fromObjectTreeDeltasType(deltaTypePrismProperty.getRealValue(), prismContext); + } + + public boolean isProcessInstanceFinished(Task task) { + return task.getWorkflowContext() != null && task.getWorkflowContext().getEndTimestamp() != null; + } + + public void setRootTaskOidImmediate(Task task, String oid, OperationResult result) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException { + Collection values = new ArrayList<>(); + if (StringUtils.isNotEmpty(oid)) { + values.add(createObjectRef(oid, TASK).asReferenceValue()); + } + task.addModificationImmediate( + DeltaBuilder.deltaFor(TaskType.class, prismContext) + .item(F_WORKFLOW_CONTEXT, F_ROOT_TASK_REF).replace(values) + .asItemDelta(), + result); + } + + public String getRootTaskOid(Task task) { + ObjectReferenceType ref = task.getWorkflowContext() != null ? task.getWorkflowContext().getRootTaskRef() : null; + return ref != null ? ref.getOid() : null; + } + + public void deleteModelOperationContext(Task task) throws SchemaException, ObjectNotFoundException { + task.setModelOperationContext(null); + } + + public void addApprovedBy(Task task, ObjectReferenceType referenceType) throws SchemaException { + addApprovedBy(task, Collections.singletonList(referenceType)); + } + + public void addApprovedBy(Task task, Collection referenceTypes) throws SchemaException { + task.addModification(DeltaBuilder.deltaFor(TaskType.class, prismContext) + .item(F_WORKFLOW_CONTEXT, F_APPROVED_BY_REF).add( + cloneListMembers(objectReferenceListToPrismReferenceValues(referenceTypes))) + .asItemDelta()); + } + + public void addApprovedBy(Task task, String oid) throws SchemaException { + ObjectReferenceType objectReferenceType = new ObjectReferenceType(); + objectReferenceType.setOid(oid); + addApprovedBy(task, objectReferenceType); + } + + public PrismReference getApprovedBy(Task task) throws SchemaException { + return task.getTaskPrismObject().findReference(new ItemPath(F_WORKFLOW_CONTEXT, F_APPROVED_BY_REF)); + } + + public List getApprovedByFromTaskTree(Task task, OperationResult result) throws SchemaException { + // we use a OID-keyed map to (1) keep not only the OID, but whole reference, but (2) eliminate uncertainty in comparing references + Map approvers = new HashMap<>(); + + List tasks = task.listSubtasksDeeply(result); + tasks.add(task); + for (Task aTask : tasks) { + PrismReference approvedBy = getApprovedBy(aTask); + if (approvedBy != null) { + for (PrismReferenceValue referenceValue : approvedBy.getValues()) { + approvers.put(referenceValue.getOid(), referenceValue); + } + } + } + + List retval = new ArrayList<>(approvers.size()); + for (PrismReferenceValue approverRefValue : approvers.values()) { + ObjectReferenceType referenceType = new ObjectReferenceType(); + referenceType.setupReferenceValue(approverRefValue.clone()); + retval.add(referenceType); + } + return retval; + } + + // handlers are stored in the list in the order they should be executed; so the last one has to be pushed first + void pushHandlers(Task task, List handlers) { + for (int i = handlers.size()-1; i >= 0; i--) { + UriStackEntry entry = handlers.get(i); + if (WAIT_FOR_TASKS_HANDLER_URI.equals(entry.getHandlerUri())) { + task.pushWaitForTasksHandlerUri(); + } else { + if (!entry.getExtensionDelta().isEmpty()) { + throw new UnsupportedOperationException("handlers with extension delta set are not supported yet"); + } + task.pushHandlerUri(entry.getHandlerUri(), entry.getSchedule(), TaskBinding.fromTaskType(entry.getBinding()), (ItemDelta) null); + } + } + } +} diff --git a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/util/MiscDataUtil.java b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/util/MiscDataUtil.java index 91f8db0977f..938416eacd4 100644 --- a/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/util/MiscDataUtil.java +++ b/model/workflow-impl/src/main/java/com/evolveum/midpoint/wf/impl/util/MiscDataUtil.java @@ -18,16 +18,17 @@ import com.evolveum.midpoint.model.api.context.ModelContext; import com.evolveum.midpoint.model.api.context.ModelElementContext; -import com.evolveum.midpoint.prism.Containerable; -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismContainerValue; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; +import com.evolveum.midpoint.model.impl.lens.LensFocusContext; +import com.evolveum.midpoint.model.impl.lens.LensProjectionContext; +import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ObjectDelta; +import com.evolveum.midpoint.prism.polystring.PolyString; import com.evolveum.midpoint.repo.api.RepositoryService; import com.evolveum.midpoint.schema.DeltaConvertor; +import com.evolveum.midpoint.schema.ResourceShadowDiscriminator; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.util.MiscSchemaUtil; +import com.evolveum.midpoint.schema.util.OidUtil; import com.evolveum.midpoint.security.api.AuthorizationConstants; import com.evolveum.midpoint.security.api.MidPointPrincipal; import com.evolveum.midpoint.security.api.SecurityEnforcer; @@ -43,19 +44,9 @@ import com.evolveum.midpoint.wf.impl.WfConfiguration; import com.evolveum.midpoint.wf.impl.activiti.ActivitiEngine; import com.evolveum.midpoint.wf.impl.processes.common.CommonProcessVariableNames; -import com.evolveum.midpoint.wf.impl.processes.common.StringHolder; -import com.evolveum.midpoint.wf.impl.processors.primary.ObjectTreeDeltas; -import com.evolveum.midpoint.wf.impl.processors.primary.PcpProcessVariableNames; -import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectTreeDeltasType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.OrgType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.RoleType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType; -import com.evolveum.midpoint.xml.ns._public.common.common_3.WorkItemType; +import com.evolveum.midpoint.wf.impl.processes.common.LightweightObjectRef; +import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; - import org.activiti.engine.ActivitiException; import org.activiti.engine.TaskService; import org.activiti.engine.form.FormProperty; @@ -65,12 +56,13 @@ import org.springframework.stereotype.Component; import javax.xml.bind.JAXBException; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import static com.evolveum.midpoint.prism.delta.ChangeType.ADD; + /** * @author mederly */ @@ -102,6 +94,15 @@ public class MiscDataUtil { @Autowired private ActivitiEngine activitiEngine; + public static ObjectReferenceType toObjectReferenceType(LightweightObjectRef ref) { + if (ref != null) { + return ref.toObjectReferenceType(); + } else { + return null; + } + } + + //region ========================================================================== Miscellaneous public PrismObject getUserByOid(String oid, OperationResult result) { if (oid == null) { return null; @@ -136,81 +137,27 @@ public String getUserNameByOid(String oid, OperationResult result) { } } - public PrismObject getRequester(Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { - String oid = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_REQUESTER_OID); - return repositoryService.getObject(UserType.class, oid, null, result); - } - - public PrismObject getObjectBefore(Map variables, PrismContext prismContext, OperationResult result) throws SchemaException, ObjectNotFoundException, JAXBException { - String objectXml = (String) variables.get(PcpProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_TO_BE_ADDED); - PrismObject object; - if (objectXml != null) { - object = prismContext.parseObject(objectXml, PrismContext.LANG_XML); - } else { - String oid = (String) variables.get(CommonProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_OID); - if (oid == null) { - return null; - } - //Validate.notNull(oid, "Object OID in process variables is null"); - object = repositoryService.getObject(ObjectType.class, oid, null, result); - } - - if (object.asObjectable() instanceof UserType) { - resolveAssignmentTargetReferences((PrismObject) object, result); - } - return object; - } - - public ObjectTreeDeltas getObjectTreeDeltas(Map variables, boolean mayBeNull) throws JAXBException, SchemaException { - ObjectTreeDeltasType deltas = getObjectTreeDeltaType(variables, mayBeNull); - return deltas != null ? ObjectTreeDeltas.fromObjectTreeDeltasType(deltas, prismContext) : null; - } - - public ObjectDelta getFocusPrimaryDelta(Map variables, boolean mayBeNull) throws JAXBException, SchemaException { - ObjectDeltaType objectDeltaType = getFocusPrimaryObjectDeltaType(variables, mayBeNull); + public ObjectDelta getFocusPrimaryDelta(WfContextType workflowContext, boolean mayBeNull) throws JAXBException, SchemaException { + ObjectDeltaType objectDeltaType = getFocusPrimaryObjectDeltaType(workflowContext, mayBeNull); return objectDeltaType != null ? DeltaConvertor.createObjectDelta(objectDeltaType, prismContext) : null; } // mayBeNull=false means that the corresponding variable must be present (not that focus must be non-null) // TODO: review/correct this! - public ObjectDeltaType getFocusPrimaryObjectDeltaType(Map variables, boolean mayBeNull) throws JAXBException, SchemaException { - ObjectTreeDeltasType deltas = getObjectTreeDeltaType(variables, mayBeNull); + public ObjectDeltaType getFocusPrimaryObjectDeltaType(WfContextType workflowContext, boolean mayBeNull) throws JAXBException, SchemaException { + ObjectTreeDeltasType deltas = getObjectTreeDeltaType(workflowContext, mayBeNull); return deltas != null ? deltas.getFocusPrimaryDelta() : null; } - public ObjectTreeDeltasType getObjectTreeDeltaType(Map variables, boolean mayBeNull) throws JAXBException, SchemaException { - StringHolder deltasXml = (StringHolder) variables.get(PcpProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_TREE_DELTAS); - if (deltasXml == null) { - if (mayBeNull) { - return null; - } else { - throw new IllegalStateException("There's no " + PcpProcessVariableNames.VARIABLE_MIDPOINT_OBJECT_TREE_DELTAS + " in process variables"); - } - } - return prismContext.parseAtomicValue( - deltasXml.getValue(), ObjectTreeDeltasType.COMPLEX_TYPE, PrismContext.LANG_XML); - } - - public PrismObject getObjectAfter(Map variables, ObjectDeltaType deltaType, PrismObject objectBefore, PrismContext prismContext, OperationResult result) throws JAXBException, SchemaException { - - ObjectDelta delta; - if (deltaType != null) { - delta = DeltaConvertor.createObjectDelta(deltaType, prismContext); - } else { - delta = getFocusPrimaryDelta(variables, true); - } - - if (delta == null) { - return null; - } - - PrismObject objectAfter = objectBefore.clone(); - delta.applyTo(objectAfter); - - if (objectAfter.asObjectable() instanceof UserType) { - resolveAssignmentTargetReferences((PrismObject) objectAfter, result); - } - return objectAfter; + public ObjectTreeDeltasType getObjectTreeDeltaType(WfContextType workflowContext, boolean mayBeNull) throws SchemaException { + WfProcessorSpecificStateType state = workflowContext.getProcessorSpecificState(); + if (mayBeNull && state == null) { + return null; + } + if (!(state instanceof WfPrimaryChangeProcessorStateType)) { + throw new IllegalStateException("Expected WfPrimaryChangeProcessorStateType but got " + state); + } + return ((WfPrimaryChangeProcessorStateType) state).getDeltasToProcess(); } public static String serializeObjectToXml(PrismObject object) { @@ -270,13 +217,28 @@ public void resolveAssignmentTargetReferences(PrismObject ob * Retrieves focus object name from the model context. */ public static String getFocusObjectName(ModelContext modelContext) { + ObjectType object = getFocusObjectNewOrOld(modelContext); + return object.getName() != null ? object.getName().getOrig() : null; + } + + public static String getFocusObjectOid(ModelContext modelContext) { + ModelElementContext fc = modelContext.getFocusContext(); + if (fc.getObjectNew() != null && fc.getObjectNew().getOid() != null) { + return fc.getObjectNew().getOid(); + } else if (fc.getObjectOld() != null && fc.getObjectOld().getOid() != null) { + return fc.getObjectOld().getOid(); + } else { + return null; + } + } + + public static ObjectType getFocusObjectNewOrOld(ModelContext modelContext) { ModelElementContext fc = modelContext.getFocusContext(); PrismObject prism = fc.getObjectNew() != null ? fc.getObjectNew() : fc.getObjectOld(); if (prism == null) { throw new IllegalStateException("No object (new or old) in model context"); } - ObjectType object = prism.asObjectable(); - return object.getName() != null ? object.getName().getOrig() : null; + return prism.asObjectable(); } public Task getShadowTask(Map variables, OperationResult result) throws SchemaException, ObjectNotFoundException { @@ -389,6 +351,7 @@ public boolean isMemberOfActivitiGroup(UserType userType, String activitiGroupId } // TODO: currently we check only the direct assignments, we need to implement more complex mechanism + @Deprecated public List getGroupsForUser(String oid, OperationResult result) throws SchemaException, ObjectNotFoundException { List retval = new ArrayList<>(); UserType userType = repositoryService.getObject(UserType.class, oid, null, result).asObjectable(); @@ -404,20 +367,56 @@ public List getGroupsForUser(String oid, OperationResult result) throws return retval; } - public PrismObject resolveObjectReferenceType(ObjectReferenceType ref, OperationResult result) { + public PrismObject resolveObjectReference(ObjectReferenceType ref, OperationResult result) { + return resolveObjectReference(ref, false, result); + } + + public PrismObject resolveAndStoreObjectReference(ObjectReferenceType ref, OperationResult result) { + return resolveObjectReference(ref, true, result); + } + + private PrismObject resolveObjectReference(ObjectReferenceType ref, boolean storeBack, OperationResult result) { + if (ref == null) { + return null; + } + if (ref.asReferenceValue().getObject() != null) { + return ref.asReferenceValue().getObject(); + } try { - return repositoryService.getObject((Class) prismContext.getSchemaRegistry().getCompileTimeClass(ref.getType()), ref.getOid(), null, result); + PrismObject object = repositoryService.getObject((Class) prismContext.getSchemaRegistry().getCompileTimeClass(ref.getType()), ref.getOid(), null, result); + if (storeBack) { + ref.asReferenceValue().setObject(object); + } + return object; } catch (ObjectNotFoundException e) { // there should be a note in result by now LoggingUtils.logException(LOGGER, "Couldn't get reference {} details because it couldn't be found", e, ref); return null; } catch (SchemaException e) { // there should be a note in result by now - LoggingUtils.logException(LOGGER, "Couldn't get reference {} details due to schema exception", e, ref); + LoggingUtils.logUnexpectedException(LOGGER, "Couldn't get reference {} details due to schema exception", e, ref); return null; } } + public ObjectReferenceType resolveObjectReferenceName(ObjectReferenceType ref, OperationResult result) { + if (ref == null || ref.getTargetName() != null) { + return ref; + } + PrismObject object; + if (ref.asReferenceValue().getObject() != null) { + object = ref.asReferenceValue().getObject(); + } else { + object = resolveObjectReference(ref, result); + if (object == null) { + return ref; + } + } + ref = ref.clone(); + ref.setTargetName(PolyString.toPolyStringType(object.getName())); + return ref; + } + public ObjectReferenceType groupIdToObjectReference(String groupId) { String parts[] = groupId.split(":"); if (parts.length != 2) { @@ -442,4 +441,37 @@ private String objectReferenceToGroupName(ObjectReferenceType ref) { } } + public void generateFocusOidIfNeeded(ModelContext modelContext, ObjectDelta change) { + if (modelContext.getFocusContext().getOid() != null) { + return; + } + + String newOid = OidUtil.generateOid(); + LOGGER.trace("This is ADD operation with no focus OID provided. Generated new OID to be used: {}", newOid); + if (change.getChangeType() != ADD) { + throw new IllegalStateException("Change type is not ADD for no-oid focus situation: " + change); + } else if (change.getObjectToAdd() == null) { + throw new IllegalStateException("Object to add is null for change: " + change); + } else if (change.getObjectToAdd().getOid() != null) { + throw new IllegalStateException("Object to add has already an OID present: " + change); + } + change.getObjectToAdd().setOid(newOid); + ((LensFocusContext) modelContext.getFocusContext()).setOid(newOid); + } + + public void generateProjectionOidIfNeeded(ModelContext modelContext, ShadowType shadow, ResourceShadowDiscriminator rsd) { + if (shadow.getOid() != null) { + return; + } + String newOid = OidUtil.generateOid(); + LOGGER.trace("This is ADD operation with no shadow OID for {} provided. Generated new OID to be used: {}", rsd, newOid); + shadow.setOid(newOid); + LensProjectionContext projCtx = ((LensProjectionContext) modelContext.findProjectionContext(rsd)); + if (projCtx == null) { + throw new IllegalStateException("No projection context for " + rsd + " could be found"); + } else if (projCtx.getOid() != null) { + throw new IllegalStateException("No projection context for " + rsd + " has already an OID: " + projCtx.getOid()); + } + projCtx.setOid(newOid); + } } diff --git a/model/workflow-impl/src/main/resources/processes/ItemApproval.bpmn20.xml b/model/workflow-impl/src/main/resources/processes/ItemApproval.bpmn20.xml index bf3e8af4f7f..407cab22e8f 100644 --- a/model/workflow-impl/src/main/resources/processes/ItemApproval.bpmn20.xml +++ b/model/workflow-impl/src/main/resources/processes/ItemApproval.bpmn20.xml @@ -30,7 +30,7 @@ diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java index 87abf967547..5d3f01f622b 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCache.java @@ -283,7 +283,10 @@ public PrismObject getShadow(String oid, PrismObject rep LOGGER.trace("Resource object fetched from resource:\n{}", resourceShadow.debugDump()); } - shadowManager.updateRepoShadow(shadowCtx, resourceShadow.asObjectable(), repositoryShadow.asObjectable(), parentResult); + repositoryShadow = shadowManager.updateShadow(shadowCtx, resourceShadow, repositoryShadow, parentResult); + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Repository shadow after update:\n{}", repositoryShadow.debugDump()); + } // Complete the shadow by adding attributes from the resource object PrismObject resultShadow = completeShadow(shadowCtx, resourceShadow, repositoryShadow, parentResult); @@ -734,7 +737,7 @@ public boolean handle(PrismObject resourceShadow) { // This determines the definitions exactly. How the repo shadow should have proper kind/intent ProvisioningContext shadowCtx = applyAttributesDefinition(ctx, repoShadow); - shadowManager.updateRepoShadow(shadowCtx, resourceShadow.asObjectable(), repoShadow.asObjectable(), parentResult); + repoShadow = shadowManager.updateShadow(shadowCtx, resourceShadow, repoShadow, parentResult); resultShadow = completeShadow(shadowCtx, resourceShadow, repoShadow, parentResult); @@ -1331,7 +1334,6 @@ void processChange(ProvisioningContext ctx, Change change, PrismObje if (oldShadow != null) { applyAttributesDefinition(ctx, oldShadow); - ShadowType oldShadowType = oldShadow.asObjectable(); LOGGER.trace("Old shadow: {}", oldShadow); @@ -1348,8 +1350,7 @@ void processChange(ProvisioningContext ctx, Change change, PrismObje PrismObject currentShadow = completeShadow(ctx, change.getCurrentShadow(), oldShadow, parentResult); change.setCurrentShadow(currentShadow); - ShadowType currentShadowType = currentShadow.asObjectable(); - shadowManager.updateRepoShadow(ctx, currentShadowType, oldShadowType, parentResult); + shadowManager.updateShadow(ctx, currentShadow, oldShadow, parentResult); } // FIXME: hack. the object delta must have oid specified. @@ -1550,13 +1551,11 @@ private PrismObject completeShadow(ProvisioningContext ctx, PrismObj PrismProperty resultAuxOcProp = resultShadow.findOrCreateProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS); resultAuxOcProp.addAll(PrismPropertyValue.cloneCollection(resourceAuxOcProp.getValues())); } - + + resultShadowType.setName(new PolyStringType(ShadowUtil.determineShadowName(resourceShadow))); if (resultShadowType.getObjectClass() == null) { resultShadowType.setObjectClass(resourceAttributesContainer.getDefinition().getTypeName()); } - if (resultShadowType.getName() == null) { - resultShadowType.setName(new PolyStringType(ShadowUtil.determineShadowName(resourceShadow))); - } if (resultShadowType.getResource() == null) { resultShadowType.setResourceRef(ObjectTypeUtil.createObjectRef(ctx.getResource())); } diff --git a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCacheProvisioner.java b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCacheProvisioner.java index 1b134291820..fde7fd39210 100644 --- a/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCacheProvisioner.java +++ b/provisioning/provisioning-impl/src/main/java/com/evolveum/midpoint/provisioning/impl/ShadowCacheProvisioner.java @@ -69,7 +69,9 @@ public String afterAddOnResource(ProvisioningContext ctx, PrismObject updateShadow(ProvisioningContext ctx, PrismObject> oldSecondaryIdentifiers = ShadowUtil.getSecondaryIdentifiers(oldShadowType); - if (oldSecondaryIdentifiers.isEmpty()){ - return; - } - ResourceAttributeContainer newSecondaryIdentifiers = ShadowUtil.getAttributesContainer(currentShadowType); - - //remember name before normalizing attributes - PolyString currentShadowName = ShadowUtil.determineShadowName(currentShadowType); - currentShadowType.setName(new PolyStringType(currentShadowName)); + public PrismObject updateShadow(ProvisioningContext ctx, PrismObject currentResourceShadow, + PrismObject oldRepoShadow, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ObjectAlreadyExistsException, ConfigurationException, CommunicationException { - Iterator> oldSecondaryIterator = oldSecondaryIdentifiers.iterator(); - Collection repoShadowDeltas = new ArrayList(); - while (oldSecondaryIterator.hasNext()){ - ResourceAttribute oldSecondaryIdentifier = oldSecondaryIterator.next(); - ResourceAttribute newSecondaryIdentifier = newSecondaryIdentifiers.findAttribute(oldSecondaryIdentifier.getElementName()); - Collection newValue = newSecondaryIdentifier.getRealValues(); - - if (!compareAttribute(ctx.getObjectClassDefinition(), newSecondaryIdentifier, oldSecondaryIdentifier)){ - PropertyDelta propertyDelta = PropertyDelta.createDelta(new ItemPath(ShadowType.F_ATTRIBUTES, oldSecondaryIdentifier.getElementName()), oldShadowType.asPrismObject().getDefinition()); - propertyDelta.addValuesToDelete(PrismPropertyValue.cloneCollection((Collection)oldSecondaryIdentifier.getValues())); - propertyDelta.addValuesToAdd(PrismPropertyValue.cloneCollection((Collection)newSecondaryIdentifier.getValues())); - repoShadowDeltas.add(propertyDelta); + RefinedObjectClassDefinition ocDef = ctx.getObjectClassDefinition(); + ObjectDelta shadowDelta = oldRepoShadow.createModifyDelta(); + PrismContainer currentResourceAttributesContainer = currentResourceShadow.findContainer(ShadowType.F_ATTRIBUTES); + PrismContainer oldRepoAttributesContainer = oldRepoShadow.findContainer(ShadowType.F_ATTRIBUTES); + for (Item currentResourceItem: currentResourceAttributesContainer.getValue().getItems()) { + if (currentResourceItem instanceof PrismProperty) { + PrismProperty currentResourceAttrProperty = (PrismProperty)currentResourceItem; + RefinedAttributeDefinition attrDef = ocDef.findAttributeDefinition(currentResourceAttrProperty.getElementName()); + if (ProvisioningUtil.shouldStoreAtributeInShadow(ocDef, attrDef.getName())) { + MatchingRule matchingRule = matchingRuleRegistry.getMatchingRule(attrDef.getMatchingRuleQName(), attrDef.getTypeName()); + PrismProperty oldRepoAttributeProperty = oldRepoAttributesContainer.findProperty(currentResourceAttrProperty.getElementName()); + if (oldRepoAttributeProperty == null ) { + PropertyDelta attrAddDelta = currentResourceAttrProperty.createDelta(); + for (PrismPropertyValue pval: currentResourceAttrProperty.getValues()) { + Object normalizedRealValue; + if (matchingRule == null) { + normalizedRealValue = pval.getValue(); + } else { + normalizedRealValue = matchingRule.normalize(pval.getValue()); + } + attrAddDelta.addValueToAdd(new PrismPropertyValue(normalizedRealValue)); + } + shadowDelta.addModification(attrAddDelta); + } else { + if (attrDef.isSingleValue()) { + Object currentResourceRealValue = currentResourceAttrProperty.getRealValue(); + Object currentResourceNormalizedRealValue; + if (matchingRule == null) { + currentResourceNormalizedRealValue = currentResourceRealValue; + } else { + currentResourceNormalizedRealValue = matchingRule.normalize(currentResourceRealValue); + } + if (!currentResourceNormalizedRealValue.equals(oldRepoAttributeProperty.getRealValue())) { + shadowDelta.addModificationReplaceProperty(currentResourceAttrProperty.getPath(), currentResourceNormalizedRealValue); + } + } else { + PrismProperty normalizedCurrentResourceAttrProperty = (PrismProperty) currentResourceAttrProperty.clone(); + if (matchingRule != null) { + for (PrismPropertyValue pval: normalizedCurrentResourceAttrProperty.getValues()) { + Object normalizedRealValue = matchingRule.normalize(pval.getValue()); + pval.setValue(normalizedRealValue); + } + } + PropertyDelta attrDiff = normalizedCurrentResourceAttrProperty.diff(oldRepoAttributeProperty); + if (attrDiff != null && !attrDiff.isEmpty()) { + shadowDelta.addModification(attrDiff); + } + + } + } + } } - } - - if (!repoShadowDeltas.isEmpty()){ - - PropertyDelta shadowNameDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_NAME, - oldShadowType.asPrismObject().getDefinition(),currentShadowName); - repoShadowDeltas.add(shadowNameDelta); - } else { - - if (!oldShadowType.getName().getOrig().equals(currentShadowType.getName().getOrig())){ - PropertyDelta shadowNameDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_NAME, - oldShadowType.asPrismObject().getDefinition(), currentShadowName); - repoShadowDeltas.add(shadowNameDelta); - + for (Item oldRepoItem: oldRepoAttributesContainer.getValue().getItems()) { + if (oldRepoItem instanceof PrismProperty) { + PrismProperty oldRepoAttrProperty = (PrismProperty)oldRepoItem; + RefinedAttributeDefinition attrDef = ocDef.findAttributeDefinition(oldRepoAttrProperty.getElementName()); + if (attrDef == null || !ProvisioningUtil.shouldStoreAtributeInShadow(ocDef, attrDef.getName())) { + // No definition for this property, it should not be in the shadow + PropertyDelta oldRepoAttrPropDelta = oldRepoAttrProperty.createDelta(); + oldRepoAttrPropDelta.addValuesToDelete((Collection)PrismPropertyValue.cloneCollection(oldRepoAttrProperty.getValues())); + shadowDelta.addModification(oldRepoAttrPropDelta); + } } } + + PolyString currentShadowName = ShadowUtil.determineShadowName(currentResourceShadow); + PolyString oldRepoShadowName = oldRepoShadow.getName(); + if (!currentShadowName.equalsOriginalValue(oldRepoShadowName)) { + PropertyDelta shadowNameDelta = PropertyDelta.createModificationReplaceProperty(ShadowType.F_NAME, + oldRepoShadow.getDefinition(),currentShadowName); + shadowDelta.addModification(shadowNameDelta); + } - PropertyDelta auxOcDelta = PrismProperty.diff( - oldShadowType.asPrismObject().findProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS), - currentShadowType.asPrismObject().findProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS)); + PropertyDelta auxOcDelta = (PropertyDelta)PrismProperty.diff( + oldRepoShadow.findProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS), + currentResourceShadow.findProperty(ShadowType.F_AUXILIARY_OBJECT_CLASS)); if (auxOcDelta != null) { - repoShadowDeltas.add(auxOcDelta); + shadowDelta.addModification(auxOcDelta); } - if (!repoShadowDeltas.isEmpty()){ - normalizeDeltas((Collection)repoShadowDeltas, ctx.getObjectClassDefinition()); - ConstraintsChecker.onShadowModifyOperation(repoShadowDeltas); - LOGGER.trace("Modifying repository shadow {}:\n{}", oldShadowType, DebugUtil.debugDump(repoShadowDeltas)); - repositoryService.modifyObject(ShadowType.class, oldShadowType.getOid(), repoShadowDeltas, parentResult); - oldShadowType.setName(new PolyStringType(currentShadowName)); - } - + if (!shadowDelta.isEmpty()) { + if (LOGGER.isTraceEnabled()) { + LOGGER.trace("Updating shadow {} with delta:\n{}", oldRepoShadow, shadowDelta.debugDump()); + } + ConstraintsChecker.onShadowModifyOperation(shadowDelta.getModifications()); + try { + repositoryService.modifyObject(ShadowType.class, oldRepoShadow.getOid(), shadowDelta.getModifications(), parentResult); + } catch (ObjectAlreadyExistsException e) { + // This should not happen for shadows + throw new SystemException(e.getMessage(), e); + } + PrismObject newRepoShadow = oldRepoShadow.clone(); + shadowDelta.applyTo(newRepoShadow); + return newRepoShadow; + + } else { + LOGGER.trace("No need to update shadow {} (empty delta)", oldRepoShadow); + return oldRepoShadow; + } } /** @@ -882,19 +929,21 @@ public void updateRepoShadow(ProvisioningContext ctx, ShadowType currentShadowTy */ public PrismObject fixShadow(ProvisioningContext ctx, PrismObject origRepoShadow, OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ConfigurationException, CommunicationException { - PrismObject repoShadow = repositoryService.getObject(ShadowType.class, origRepoShadow.getOid(), null, parentResult); - ProvisioningContext shadowCtx = ctx.spawn(repoShadow); + PrismObject currentRepoShadow = repositoryService.getObject(ShadowType.class, origRepoShadow.getOid(), null, parentResult); + ProvisioningContext shadowCtx = ctx.spawn(currentRepoShadow); RefinedObjectClassDefinition ocDef = shadowCtx.getObjectClassDefinition(); - PrismContainer attributesContainer = repoShadow.findContainer(ShadowType.F_ATTRIBUTES); + PrismContainer attributesContainer = currentRepoShadow.findContainer(ShadowType.F_ATTRIBUTES); if (attributesContainer != null) { - ObjectDelta shadowDelta = repoShadow.createModifyDelta(); + ObjectDelta shadowDelta = currentRepoShadow.createModifyDelta(); for (Item item: attributesContainer.getValue().getItems()) { if (item instanceof PrismProperty) { PrismProperty attrProperty = (PrismProperty)item; RefinedAttributeDefinition attrDef = ocDef.findAttributeDefinition(attrProperty.getElementName()); if (attrDef == null) { // No definition for this property, it should not be in the shadow - shadowDelta.addModificationDeleteProperty(attrProperty.getPath(), attrProperty.getRealValues()); + PropertyDelta oldRepoAttrPropDelta = attrProperty.createDelta(); + oldRepoAttrPropDelta.addValuesToDelete((Collection)PrismPropertyValue.cloneCollection(attrProperty.getValues())); + shadowDelta.addModification(oldRepoAttrPropDelta); } else { MatchingRule matchingRule = matchingRuleRegistry.getMatchingRule(attrDef.getMatchingRuleQName(), attrDef.getTypeName()); List valuesToAdd = null; @@ -939,14 +988,14 @@ public PrismObject fixShadow(ProvisioningContext ctx, PrismObject accountRepo) { @Test public void test101AddAccountWithoutName() throws Exception { - TestUtil.displayTestTile("test101AddAccountWithoutName"); + final String TEST_NAME = "test101AddAccountWithoutName"; + TestUtil.displayTestTile(TEST_NAME); // GIVEN - Task syncTask = taskManager.createTaskInstance(TestDummy.class.getName() - + ".test101AddAccountWithoutName"); - OperationResult result = new OperationResult(TestDummy.class.getName() - + ".test101AddAccountWithoutName"); + Task syncTask = taskManager.createTaskInstance(TestDummy.class.getName() + "." + TEST_NAME); + OperationResult result = new OperationResult(TestDummy.class.getName() + "." + TEST_NAME); syncServiceMock.reset(); ShadowType account = parseObjectType(ACCOUNT_MORGAN_FILE, ShadowType.class); @@ -1126,9 +1125,11 @@ public void test101AddAccountWithoutName() throws Exception { display("Adding shadow", account.asPrismObject()); // WHEN + TestUtil.displayWhen(TEST_NAME); String addedObjectOid = provisioningService.addObject(account.asPrismObject(), null, null, syncTask, result); // THEN + TestUtil.displayThen(TEST_NAME); result.computeStatus(); display("add object result", result); TestUtil.assertSuccess("addObject has failed (result)", result); @@ -1141,8 +1142,10 @@ public void test101AddAccountWithoutName() throws Exception { syncServiceMock.assertNotifySuccessOnly(); + TestUtil.displayWhen(TEST_NAME); ShadowType provisioningAccountType = provisioningService.getObject(ShadowType.class, ACCOUNT_MORGAN_OID, null, syncTask, result).asObjectable(); + TestUtil.displayThen(TEST_NAME); display("account from provisioning", provisioningAccountType); PrismAsserts.assertEqualsPolyString("Account name was not generated (provisioning)", transformNameFromResource(ACCOUNT_MORGAN_NAME), provisioningAccountType.getName()); diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/CertificationTest.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/CertificationTest.java index bd547fa55fb..648abfde642 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/CertificationTest.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/CertificationTest.java @@ -127,7 +127,7 @@ public void test108AddCampaignOverwriteExisting() throws Exception { public void test200ModifyCampaignProperties() throws Exception { OperationResult result = new OperationResult("test200ModifyCampaignProperties"); - List modifications = new ArrayList<>(); + List> modifications = new ArrayList<>(); modifications.add(createModificationReplaceProperty(F_NAME, campaignDef, new PolyString("Campaign 1+", "campaign 1"))); modifications.add(createModificationReplaceProperty(F_STATE, campaignDef, IN_REVIEW_STAGE)); @@ -138,7 +138,7 @@ public void test200ModifyCampaignProperties() throws Exception { public void test210ModifyCaseProperties() throws Exception { OperationResult result = new OperationResult("test210ModifyCaseProperties"); - List modifications = new ArrayList<>(); + List> modifications = new ArrayList<>(); ItemPath case1 = new ItemPath(F_CASE).subPath(new IdItemPathSegment(1L)); modifications.add(createModificationReplaceProperty(case1.subPath(F_CURRENT_STAGE_OUTCOME), campaignDef, DELEGATE)); modifications.add(createModificationReplaceProperty(case1.subPath(F_CURRENT_STAGE_NUMBER), campaignDef, 300)); @@ -150,7 +150,7 @@ public void test210ModifyCaseProperties() throws Exception { public void test220ModifyDecisionProperties() throws Exception { OperationResult result = new OperationResult("test220ModifyDecisionProperties"); - List modifications = new ArrayList<>(); + List> modifications = new ArrayList<>(); ItemPath d1 = new ItemPath(F_CASE).subPath(1L).subPath(F_DECISION).subPath(1L); modifications.add(createModificationReplaceProperty(d1.subPath(F_RESPONSE), campaignDef, DELEGATE)); modifications.add(createModificationReplaceProperty(d1.subPath(F_COMMENT), campaignDef, "hi")); @@ -162,7 +162,7 @@ public void test220ModifyDecisionProperties() throws Exception { public void test230ModifyAllLevels() throws Exception { OperationResult result = new OperationResult("test230ModifyAllLevels"); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_NAME).replace(new PolyString("Campaign 2", "campaign 2")) .item(F_STATE).replace(IN_REMEDIATION) .item(F_CASE, 2, F_CURRENT_STAGE_OUTCOME).replace(NO_RESPONSE) @@ -191,7 +191,7 @@ public void test240AddCases() throws Exception { case100.getCurrentReviewerRef().add(createObjectRef("100789", ObjectTypes.USER)); case100.setCurrentStageNumber(1); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE).add(caseNoId, case100) .asItemDeltas(); @@ -205,7 +205,7 @@ public void test242DeleteCase() throws Exception { AccessCertificationCaseType case7 = new AccessCertificationCaseType(); case7.setId(7L); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE).delete(case7) .asItemDeltas(); @@ -221,7 +221,7 @@ public void test244ModifyCase() throws Exception { PrismReferenceValue reviewerToDelete = createObjectRef("100789", ObjectTypes.USER).asReferenceValue(); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, 100, F_CURRENT_REVIEWER_REF).delete(reviewerToDelete) .asItemDeltas(); @@ -249,7 +249,7 @@ public void test248AddDeleteModifyCase() throws Exception { AccessCertificationCaseType case100 = new AccessCertificationCaseType(); case100.setId(100L); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE).add(caseNoId, case110).delete(case100) .item(F_CASE, 3, F_CURRENT_STAGE_NUMBER).replace(400) .asItemDeltas(); @@ -273,7 +273,7 @@ public void test250AddDeleteModifyResponse() throws Exception { AccessCertificationDecisionType dec1 = new AccessCertificationDecisionType(); dec1.setId(1L); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, 6, F_DECISION).add(decNoId, dec200) .item(F_CASE, 6, F_DECISION).delete(dec1) .item(F_CASE, 6, F_DECISION, 2, F_RESPONSE).replace(ACCEPT) @@ -291,7 +291,7 @@ public void test260ReplaceDecisionsExistingId() throws Exception { dec200.setStageNumber(44); dec200.setReviewerRef(createObjectRef("999999", ObjectTypes.USER)); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, 6, F_DECISION).replace(dec200) .asItemDeltas(); @@ -311,7 +311,7 @@ public void test265ReplaceDecisionsNewId() throws Exception { dec251.setId(251L); dec251.setStageNumber(1); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE, 6, F_DECISION).replace(dec250, dec251) .asItemDeltas(); @@ -340,7 +340,7 @@ public void test270ReplaceCase() throws Exception { caseNoId.getDecision().add(dec777); caseNoId.getDecision().add(decNoId); - List modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(AccessCertificationCampaignType.class, prismContext) .item(F_CASE).replace(caseNoId) .asItemDeltas(); @@ -492,7 +492,7 @@ public void test900DeleteCampaign() throws Exception { AssertJUnit.assertTrue(result.isSuccess()); } - protected void executeAndCheckModification(List modifications, OperationResult result, int versionDelta) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, IOException { + protected void executeAndCheckModification(List> modifications, OperationResult result, int versionDelta) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, IOException { PrismObject before = getFullCampaign(campaign1Oid, result); int expectedVersion = Integer.parseInt(before.getVersion()) + versionDelta; List savedModifications = (List) CloneUtil.cloneCollectionMembers(modifications); diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/LookupTableTest.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/LookupTableTest.java index 42875e84e39..9998f8745e5 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/LookupTableTest.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/LookupTableTest.java @@ -101,7 +101,7 @@ public void test108AddTableOverwriteExisting() throws Exception { public void test200ModifyTableProperties() throws Exception { OperationResult result = new OperationResult("test200ModifyTableProperties"); - List modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) .item(F_NAME).replace(new PolyString("Table 1", "table 1")) .asItemDeltas(); @@ -112,7 +112,7 @@ public void test200ModifyTableProperties() throws Exception { public void test210ModifyRowProperties() throws Exception { OperationResult result = new OperationResult("test210ModifyRowProperties"); - List modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) .item(F_ROW, 1, F_KEY).replace("key 1") .item(F_ROW, 1, F_LAST_CHANGE_TIMESTAMP).replace() .asItemDeltas(); @@ -124,7 +124,7 @@ public void test210ModifyRowProperties() throws Exception { public void test230ModifyTableAndRow() throws Exception { OperationResult result = new OperationResult("test230ModifyTableAndRow"); - List modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) .item(F_NAME).replace("Table 111", "table 111") .item(F_ROW, 2, F_KEY).replace("key 2") .item(F_ROW, 2, F_VALUE).replace("value 2") @@ -153,7 +153,7 @@ public void test240AddRows() throws Exception { row4.setValue("value 4"); row4.setLastChangeTimestamp(XmlTypeConverter.createXMLGregorianCalendar(new Date(99, 3, 5))); - List modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) .item(F_ROW).add(rowNoId, rowNoId2, row4) .asItemDeltas(); @@ -169,7 +169,7 @@ public void test242DeleteRow() throws Exception { LookupTableRowType row3 = new LookupTableRowType(prismContext); row3.setId(3L); - List modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) .item(F_ROW).delete(row3) .asItemDeltas(); @@ -191,7 +191,7 @@ public void test248AddDeleteModifyRows() throws Exception { LookupTableRowType row4 = new LookupTableRowType(prismContext); row4.setId(4L); - List modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) .item(F_ROW).add(rowNoId, row5).delete(row4) .asItemDeltas(); @@ -208,7 +208,7 @@ public void test260ReplaceRowsExistingId() throws Exception { row5.setValue("value 5 plus"); row5.setLastChangeTimestamp(XmlTypeConverter.createXMLGregorianCalendar(new Date(99, 3, 10))); - List modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) .item(F_ROW).replace(row5) .asItemDeltas(); @@ -224,7 +224,7 @@ public void test265ReplaceRowsNewId() throws Exception { rowNoId.setValue("value now plus"); rowNoId.setLastChangeTimestamp(XmlTypeConverter.createXMLGregorianCalendar(new Date(99, 3, 15))); - List modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) + List> modifications = DeltaBuilder.deltaFor(LookupTableType.class, prismContext) .item(F_ROW).replace(rowNoId) .asItemDeltas(); @@ -246,7 +246,7 @@ private void checkTable(String tableOid, PrismObject expectedOb PrismAsserts.assertEquivalent("Table is not as expected", expectedObject, table); } - protected void executeAndCheckModification(List modifications, OperationResult result, int versionDelta) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, IOException { + protected void executeAndCheckModification(List> modifications, OperationResult result, int versionDelta) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException, IOException { PrismObject before = getFullTable(tableOid, result); repositoryService.modifyObject(LookupTableType.class, tableOid, modifications, result); @@ -254,7 +254,7 @@ protected void executeAndCheckModification(List modifications, Operat checkTable(tableOid, result, before, modifications, Integer.parseInt(before.getVersion()) + versionDelta); } - private void checkTable(String oid, OperationResult result, PrismObject expectedObject, List modifications, int expectedVersion) throws SchemaException, ObjectNotFoundException, IOException { + private void checkTable(String oid, OperationResult result, PrismObject expectedObject, List> modifications, int expectedVersion) throws SchemaException, ObjectNotFoundException, IOException { expectedObject.setOid(oid); if (modifications != null) { ItemDelta.applyTo(modifications, expectedObject); diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/QueryInterpreter2Test.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/QueryInterpreter2Test.java index b744f59dc06..0d3f805c3b1 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/QueryInterpreter2Test.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/QueryInterpreter2Test.java @@ -732,6 +732,86 @@ public void test080QueryExistsAssignment() throws Exception { } } + @Test + public void test090QuerySingleAssignmentWithTargetAndTenant() throws Exception { + Session session = open(); + + try { + ObjectQuery query = QueryBuilder.queryFor(UserType.class, prismContext) + .exists(F_ASSIGNMENT) + .item(AssignmentType.F_TARGET_REF).ref("target-oid-123") + .and().item(AssignmentType.F_TENANT_REF).ref("tenant-oid-456") + .build(); + + String real = getInterpretedQuery2(session, UserType.class, query); + String expected = "select\n" + + " u.fullObject,\n" + + " u.stringsCount,\n" + + " u.longsCount,\n" + + " u.datesCount,\n" + + " u.referencesCount,\n" + + " u.polysCount,\n" + + " u.booleansCount\n" + + "from\n" + + " RUser u\n" + + " left join u.assignments a with a.assignmentOwner = :assignmentOwner\n" + + "where\n" + + " (\n" + + " (\n" + + " a.targetRef.targetOid = :targetOid and\n" + + " a.targetRef.relation = :relation\n" + + " ) and\n" + + " (\n" + + " u.tenantRef.targetOid = :targetOid2 and\n" + + " u.tenantRef.relation = :relation2\n" + + " )\n" + + " )\n"; + assertEqualsIgnoreWhitespace(expected, real); + } finally { + close(session); + } + } + + @Test + public void test092QueryAssignmentsWithTargetAndTenant() throws Exception { + Session session = open(); + + try { + ObjectQuery query = QueryBuilder.queryFor(UserType.class, prismContext) + .item(UserType.F_ASSIGNMENT, AssignmentType.F_TARGET_REF).ref("target-oid-123") + .and().item(UserType.F_ASSIGNMENT, AssignmentType.F_TENANT_REF).ref("tenant-oid-456") + .build(); + + String real = getInterpretedQuery2(session, UserType.class, query); + String expected = "select\n" + + " u.fullObject,\n" + + " u.stringsCount,\n" + + " u.longsCount,\n" + + " u.datesCount,\n" + + " u.referencesCount,\n" + + " u.polysCount,\n" + + " u.booleansCount\n" + + "from\n" + + " RUser u\n" + + " left join u.assignments a with a.assignmentOwner = :assignmentOwner\n" + + " left join u.assignments a2 with a2.assignmentOwner = :assignmentOwner2\n" + + "where\n" + + " (\n" + + " (\n" + + " a.targetRef.targetOid = :targetOid and\n" + + " a.targetRef.relation = :relation\n" + + " ) and\n" + + " (\n" + + " a2.tenantRef.targetOid = :targetOid2 and\n" + + " a2.tenantRef.relation = :relation2\n" + + " )\n" + + " )\n"; + assertEqualsIgnoreWhitespace(expected, real); + } finally { + close(session); + } + } + @Test public void test100QueryObjectByName() throws Exception { Session session = open(); diff --git a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/util/SimpleTaskAdapter.java b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/util/SimpleTaskAdapter.java index 79a14795804..a89a8d4dfda 100644 --- a/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/util/SimpleTaskAdapter.java +++ b/repo/repo-sql-impl-test/src/test/java/com/evolveum/midpoint/repo/sql/util/SimpleTaskAdapter.java @@ -777,4 +777,26 @@ public void startCollectingOperationStatsFromStoredValues(boolean enableIteratio public void storeOperationStats() { } + + @Override + public void initializeWorkflowContextImmediate(String processInstanceId, OperationResult result) throws SchemaException { + } + + @Override public void addModification(ItemDelta delta) throws SchemaException { + } + + @Override public void addModifications(Collection> deltas) throws SchemaException { + + } + + @Override public void addModificationImmediate(ItemDelta delta, OperationResult parentResult) throws SchemaException { + } + + @Override + public WfContextType getWorkflowContext() { + return null; + } + + @Override public void setWorkflowContext(WfContextType context) throws SchemaException { + } } diff --git a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RTask.java b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RTask.java index 638e0177c47..f07f156076e 100644 --- a/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RTask.java +++ b/repo/repo-sql-impl/src/main/java/com/evolveum/midpoint/repo/sql/data/common/RTask.java @@ -22,6 +22,7 @@ import com.evolveum.midpoint.repo.sql.data.common.embedded.RPolyString; import com.evolveum.midpoint.repo.sql.data.common.enums.*; import com.evolveum.midpoint.repo.sql.query.definition.JaxbName; +import com.evolveum.midpoint.repo.sql.query.definition.JaxbPath; import com.evolveum.midpoint.repo.sql.util.DtoTranslationException; import com.evolveum.midpoint.repo.sql.util.IdGeneratorResult; import com.evolveum.midpoint.repo.sql.util.MidPointJoinedPersister; @@ -30,6 +31,7 @@ import com.evolveum.midpoint.schema.SelectorOptions; import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.WfContextType; import org.hibernate.annotations.Cascade; import org.hibernate.annotations.ForeignKey; import org.hibernate.annotations.Index; @@ -45,6 +47,13 @@ * @author lazyman */ @Entity +@Table(name = "m_task", indexes = { + @javax.persistence.Index(name = "iTaskWfProcessInstanceId", columnList = "wfProcessInstanceId"), + @javax.persistence.Index(name = "iTaskWfStartTimestamp", columnList = "wfStartTimestamp"), + @javax.persistence.Index(name = "iTaskWfEndTimestamp", columnList = "wfEndTimestamp"), + @javax.persistence.Index(name = "iTaskWfRequesterOid", columnList = "wfRequesterRef_targetOid"), + @javax.persistence.Index(name = "iTaskWfObjectOid", columnList = "wfObjectRef_targetOid"), + @javax.persistence.Index(name = "iTaskWfTargetOid", columnList = "wfTargetRef_targetOid") }) @ForeignKey(name = "fk_task") @Persister(impl = MidPointJoinedPersister.class) public class RTask extends RObject implements OperationResult { @@ -73,6 +82,14 @@ public class RTask extends RObject implements OperationResult { private Set dependent; private RTaskWaitingReason waitingReason; + // workflow-related information (note: objectRef is already present in task information) + private String wfProcessInstanceId; + private REmbeddedReference wfRequesterRef; + private REmbeddedReference wfObjectRef; + private REmbeddedReference wfTargetRef; + private XMLGregorianCalendar wfStartTimestamp; + private XMLGregorianCalendar wfEndTimestamp; + @ElementCollection @ForeignKey(name = "fk_task_dependent") @CollectionTable(name = "m_task_dependent", joinColumns = { @@ -146,6 +163,39 @@ public RPolyString getName() { return name; } + @JaxbPath(itemPath = { @JaxbName(localPart = "workflowContext"), @JaxbName(localPart = "processInstanceId") }) + public String getWfProcessInstanceId() { + return wfProcessInstanceId; + } + + @JaxbPath(itemPath = { @JaxbName(localPart = "workflowContext"), @JaxbName(localPart = "requesterRef") }) + @Embedded + public REmbeddedReference getWfRequesterRef() { + return wfRequesterRef; + } + + @JaxbPath(itemPath = { @JaxbName(localPart = "workflowContext"), @JaxbName(localPart = "objectRef") }) + @Embedded + public REmbeddedReference getWfObjectRef() { + return wfObjectRef; + } + + @JaxbPath(itemPath = { @JaxbName(localPart = "workflowContext"), @JaxbName(localPart = "targetRef") }) + @Embedded + public REmbeddedReference getWfTargetRef() { + return wfTargetRef; + } + + @JaxbPath(itemPath = { @JaxbName(localPart = "workflowContext"), @JaxbName(localPart = "startTimestamp") }) + public XMLGregorianCalendar getWfStartTimestamp() { + return wfStartTimestamp; + } + + @JaxbPath(itemPath = { @JaxbName(localPart = "workflowContext"), @JaxbName(localPart = "endTimestamp") }) + public XMLGregorianCalendar getWfEndTimestamp() { + return wfEndTimestamp; + } + public void setName(RPolyString name) { this.name = name; } @@ -174,6 +224,30 @@ public void setCategory(String category) { this.category = category; } + public void setWfProcessInstanceId(String wfProcessInstanceId) { + this.wfProcessInstanceId = wfProcessInstanceId; + } + + public void setWfRequesterRef(REmbeddedReference wfRequesterRef) { + this.wfRequesterRef = wfRequesterRef; + } + + public void setWfObjectRef(REmbeddedReference wfObjectRef) { + this.wfObjectRef = wfObjectRef; + } + + public void setWfTargetRef(REmbeddedReference wfTargetRef) { + this.wfTargetRef = wfTargetRef; + } + + public void setWfStartTimestamp(XMLGregorianCalendar wfStartTimestamp) { + this.wfStartTimestamp = wfStartTimestamp; + } + + public void setWfEndTimestamp(XMLGregorianCalendar wfEndTimestamp) { + this.wfEndTimestamp = wfEndTimestamp; + } + public String getHandlerUri() { return handlerUri; } @@ -289,6 +363,12 @@ public boolean equals(Object o) { if (waitingReason != null ? !waitingReason.equals(rTask.waitingReason) : rTask.waitingReason != null) return false; if (status != rTask.status) return false; + if (wfRequesterRef != null ? !wfRequesterRef.equals(rTask.wfRequesterRef) : rTask.wfRequesterRef != null) return false; + if (wfObjectRef != null ? !wfObjectRef.equals(rTask.wfObjectRef) : rTask.wfObjectRef != null) return false; + if (wfTargetRef != null ? !wfTargetRef.equals(rTask.wfTargetRef) : rTask.wfTargetRef != null) return false; + if (wfProcessInstanceId != null ? !wfProcessInstanceId.equals(rTask.wfProcessInstanceId) : rTask.wfProcessInstanceId != null) return false; + if (wfStartTimestamp != null ? !wfStartTimestamp.equals(rTask.wfStartTimestamp) : rTask.wfStartTimestamp != null) return false; + if (wfEndTimestamp != null ? !wfEndTimestamp.equals(rTask.wfEndTimestamp) : rTask.wfEndTimestamp != null) return false; return true; } @@ -342,6 +422,16 @@ public static void copyFromJAXB(TaskType jaxb, RTask repo, PrismContext prismCon repo.setWaitingReason(RUtil.getRepoEnumValue(jaxb.getWaitingReason(), RTaskWaitingReason.class)); repo.setDependent(RUtil.listToSet(jaxb.getDependent())); + WfContextType wfc = jaxb.getWorkflowContext(); + if (wfc != null) { + repo.setWfProcessInstanceId(wfc.getProcessInstanceId()); + repo.setWfRequesterRef(RUtil.jaxbRefToEmbeddedRepoRef(wfc.getRequesterRef(), prismContext)); + repo.setWfObjectRef(RUtil.jaxbRefToEmbeddedRepoRef(wfc.getObjectRef(), prismContext)); + repo.setWfTargetRef(RUtil.jaxbRefToEmbeddedRepoRef(wfc.getTargetRef(), prismContext)); + repo.setWfStartTimestamp(wfc.getStartTimestamp()); + repo.setWfEndTimestamp(wfc.getEndTimestamp()); + } + RUtil.copyResultFromJAXB(taskDefinition, jaxb.F_RESULT, jaxb.getResult(), repo, prismContext); } diff --git a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/IntegrationTestTools.java b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/IntegrationTestTools.java index 425db40e2fa..6a06e70c883 100644 --- a/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/IntegrationTestTools.java +++ b/repo/repo-test-util/src/main/java/com/evolveum/midpoint/test/IntegrationTestTools.java @@ -18,15 +18,7 @@ import com.evolveum.icf.dummy.resource.DummyGroup; import com.evolveum.icf.dummy.resource.ScriptHistoryEntry; import com.evolveum.midpoint.common.refinery.RefinedResourceSchema; -import com.evolveum.midpoint.prism.ConsistencyCheckScope; -import com.evolveum.midpoint.prism.PrismContainer; -import com.evolveum.midpoint.prism.PrismContainerDefinition; -import com.evolveum.midpoint.prism.PrismContext; -import com.evolveum.midpoint.prism.PrismObject; -import com.evolveum.midpoint.prism.PrismProperty; -import com.evolveum.midpoint.prism.PrismPropertyDefinition; -import com.evolveum.midpoint.prism.PrismPropertyValue; -import com.evolveum.midpoint.prism.PrismReferenceDefinition; +import com.evolveum.midpoint.prism.*; import com.evolveum.midpoint.prism.delta.ObjectDelta; import com.evolveum.midpoint.prism.match.MatchingRule; import com.evolveum.midpoint.prism.path.ItemPath; @@ -500,6 +492,13 @@ public static void display(String title, Object value) { LOGGER.debug(OBJECT_TITLE_LOG_PREFIX + title + "\n" + SchemaDebugUtil.prettyPrint(value)); } + + public static void display(String title, Containerable value) { + System.out.println(OBJECT_TITLE_OUT_PREFIX + title); + System.out.println(SchemaDebugUtil.prettyPrint(value.asPrismContainerValue().debugDump())); + LOGGER.debug(OBJECT_TITLE_LOG_PREFIX + title + "\n" + + SchemaDebugUtil.prettyPrint(value.asPrismContainerValue().debugDump())); + } public static void display(String title, Throwable e) { String stackTrace = ExceptionUtils.getStackTrace(e); diff --git a/repo/task-api/src/main/java/com/evolveum/midpoint/task/api/Task.java b/repo/task-api/src/main/java/com/evolveum/midpoint/task/api/Task.java index 11d49d7f789..a6b5269821a 100644 --- a/repo/task-api/src/main/java/com/evolveum/midpoint/task/api/Task.java +++ b/repo/task-api/src/main/java/com/evolveum/midpoint/task/api/Task.java @@ -909,7 +909,11 @@ public void setResultImmediate(OperationResult result, OperationResult parentRes void setModelOperationContext(LensContextType modelOperationContext) throws SchemaException; - // ====================================================================================== Other methods + // temporary! + void initializeWorkflowContextImmediate(String processInstanceId, OperationResult result) + throws SchemaException, ObjectNotFoundException; + + // ====================================================================================== Other methods /** * Returns backing task prism object. @@ -930,6 +934,22 @@ public void setResultImmediate(OperationResult result, OperationResult parentRes */ public void refresh(OperationResult parentResult) throws ObjectNotFoundException, SchemaException; + /** + * Changes in-memory representation immediately and schedules a corresponding batched modification. + * @param delta + * @throws SchemaException + */ + void addModification(ItemDelta delta) throws SchemaException; + void addModifications(Collection> deltas) throws SchemaException; + + /** + * Changes in-memory and in-repo representations immediately. + * @param delta + * @param parentResult + * @throws SchemaException + */ + void addModificationImmediate(ItemDelta delta, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException; + /** * Saves modifications done against the in-memory version of the task into the repository. */ @@ -964,4 +984,8 @@ void savePendingModifications(OperationResult parentResult) throws ObjectNotFoun void startCollectingOperationStatsFromStoredValues(boolean enableIterationStatistics, boolean enableSynchronizationStatistics, boolean enableActionsExecutedStatistics); void storeOperationStats(); + + WfContextType getWorkflowContext(); + + void setWorkflowContext(WfContextType context) throws SchemaException; } diff --git a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskQuartzImpl.java b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskQuartzImpl.java index 087779685bf..3410ab45651 100644 --- a/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskQuartzImpl.java +++ b/repo/task-quartz-impl/src/main/java/com/evolveum/midpoint/task/quartzimpl/TaskQuartzImpl.java @@ -89,6 +89,7 @@ import java.util.concurrent.Future; import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_MODEL_OPERATION_CONTEXT; +import static com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType.F_WORKFLOW_CONTEXT; /** * Implementation of a Task. @@ -186,7 +187,7 @@ private TaskQuartzImpl(TaskManagerQuartzImpl taskManager) { */ TaskQuartzImpl(TaskManagerQuartzImpl taskManager, LightweightIdentifier taskIdentifier, String operationName) { this(taskManager); - this.repositoryService = null; + this.repositoryService = taskManager.getRepositoryService(); this.taskPrism = createPrism(); setTaskIdentifier(taskIdentifier.toString()); @@ -296,9 +297,33 @@ public void addPendingModification(ItemDelta delta) { ItemDelta.merge(pendingModifications, delta); } + @Override + public void addModification(ItemDelta delta) throws SchemaException { + addPendingModification(delta); + delta.applyTo(taskPrism); + } + + @Override + public void addModifications(Collection> deltas) throws SchemaException { + for (ItemDelta delta : deltas) { + addPendingModification(delta); + delta.applyTo(taskPrism); + } + } + + @Override + public void addModificationImmediate(ItemDelta delta, OperationResult parentResult) throws SchemaException, ObjectAlreadyExistsException, ObjectNotFoundException { + addPendingModification(delta); + delta.applyTo(taskPrism); + savePendingModifications(parentResult); + } + @Override public void savePendingModifications(OperationResult parentResult) throws ObjectNotFoundException, SchemaException, ObjectAlreadyExistsException { + if (isTransient()) { + return; + } if (pendingModifications != null) { synchronized (pendingModifications) { // todo perhaps we should put something like this at more places here... if (!pendingModifications.isEmpty()) { @@ -1979,6 +2004,57 @@ public void setModelOperationContextTransient(LensContextType value) { .asItemDelta(); } } + + /* + * Workflow context + */ + + public void setWorkflowContext(WfContextType value) throws SchemaException { + processModificationBatched(setWorkflowContextAndPrepareDelta(value)); + } + + //@Override + public void setWorkflowContextImmediate(WfContextType value, OperationResult parentResult) + throws ObjectNotFoundException, SchemaException { + try { + processModificationNow(setWorkflowContextAndPrepareDelta(value), parentResult); + } catch (ObjectAlreadyExistsException ex) { + throw new SystemException(ex); + } + } + + public void setWorkflowContextTransient(WfContextType value) { + taskPrism.asObjectable().setWorkflowContext(value); + } + + private ItemDelta setWorkflowContextAndPrepareDelta(WfContextType value) throws SchemaException { + setWorkflowContextTransient(value); + if (!isPersistent()) { + return null; + } + if (value != null) { + return DeltaBuilder.deltaFor(TaskType.class, getPrismContext()) + .item(F_WORKFLOW_CONTEXT).replace(value.asPrismContainerValue().clone()) + .asItemDelta(); + } else { + return DeltaBuilder.deltaFor(TaskType.class, getPrismContext()) + .item(F_WORKFLOW_CONTEXT).replace() + .asItemDelta(); + } + } + + @Override + public WfContextType getWorkflowContext() { + return taskPrism.asObjectable().getWorkflowContext(); + } + + @Override + public void initializeWorkflowContextImmediate(String processInstanceId, OperationResult result) + throws SchemaException, ObjectNotFoundException { + WfContextType wfContextType = new WfContextType(getPrismContext()); + wfContextType.setProcessInstanceId(processInstanceId); + setWorkflowContextImmediate(wfContextType, result); + } // @Override // public PrismReference getRequesteeRef() { diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractAdLdapTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractAdLdapTest.java index 76d36dc6986..27d2bd5013f 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractAdLdapTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractAdLdapTest.java @@ -265,6 +265,7 @@ public void test000Sanity() throws Exception { cleanupDelete(toAccountDn(USER_CPTBARBOSSA_USERNAME, USER_CPTBARBOSSA_FULL_NAME)); cleanupDelete(toAccountDn(USER_GUYBRUSH_USERNAME, USER_GUYBRUSH_FULL_NAME)); cleanupDelete(toGroupDn(GROUP_MELEE_ISLAND_NAME)); + cleanupDelete(toGroupDn(GROUP_FOOLS_CN)); } @Test diff --git a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java index bc6809b20ce..b7b17393ed8 100644 --- a/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java +++ b/testing/conntest/src/test/java/com/evolveum/midpoint/testing/conntest/AbstractLdapSynchronizationTest.java @@ -1,6 +1,6 @@ package com.evolveum.midpoint.testing.conntest; /* - * Copyright (c) 2010-2015 Evolveum + * Copyright (c) 2010-2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -140,11 +140,11 @@ public abstract class AbstractLdapSynchronizationTest extends AbstractLdapTest { protected static final String ACCOUNT_HTM_UID = "htm"; protected static final String ACCOUNT_HTM_CN = "Horatio Torquemada Marley"; - private static final String GROUP_MONKEYS_CN = "monkeys"; - private static final String GROUP_MONKEYS_DESCRIPTION = "Monkeys of Monkey Island"; + protected static final String GROUP_MONKEYS_CN = "monkeys"; + protected static final String GROUP_MONKEYS_DESCRIPTION = "Monkeys of Monkey Island"; - private static final String GROUP_FOOLS_CN = "fools"; - private static final String GROUP_FOOLS_DESCRIPTION = "not quite the shilling"; + protected static final String GROUP_FOOLS_CN = "fools"; + protected static final String GROUP_FOOLS_DESCRIPTION = "not quite the shilling"; protected abstract void assertStepSyncToken(String syncTaskOid, int step, long tsStart, long tsEnd) throws ObjectNotFoundException, SchemaException;