From a00289c0ab49cc85e89666c756afaf7422ffd885 Mon Sep 17 00:00:00 2001 From: BerndBreier <33351391+BerndBreier@users.noreply.github.com> Date: Mon, 26 Feb 2018 16:53:22 +0100 Subject: [PATCH] TSK-315 Store custom properties as JSON Map in DB --- lib/taskana-core/pom.xml | 6 +- .../src/main/java/pro/taskana/Attachment.java | 5 +- .../src/main/java/pro/taskana/Task.java | 10 +- .../java/pro/taskana/impl/AttachmentImpl.java | 6 +- .../main/java/pro/taskana/impl/TaskImpl.java | 7 +- .../impl/persistence/MapTypeHandler.java | 63 ++++-------- .../taskana/mappings/AttachmentMapper.java | 16 +++- .../java/pro/taskana/mappings/TaskMapper.java | 15 ++- .../src/main/resources/sql/taskana-schema.sql | 4 +- .../test/java/acceptance/AbstractAccTest.java | 6 +- .../acceptance/task/CreateTaskAccTest.java | 96 ++++++++++++++++++- 11 files changed, 169 insertions(+), 65 deletions(-) diff --git a/lib/taskana-core/pom.xml b/lib/taskana-core/pom.xml index b2cfce021..73ba68c1d 100644 --- a/lib/taskana-core/pom.xml +++ b/lib/taskana-core/pom.xml @@ -128,7 +128,11 @@ slf4j-api 1.7.25 - + + org.json + json + 20180130 + junit diff --git a/lib/taskana-core/src/main/java/pro/taskana/Attachment.java b/lib/taskana-core/src/main/java/pro/taskana/Attachment.java index 04b48094e..403a16c54 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/Attachment.java +++ b/lib/taskana-core/src/main/java/pro/taskana/Attachment.java @@ -103,7 +103,7 @@ public interface Attachment { * * @return customAttributes as {@link Map} */ - Map getCustomAttributes(); + Map getCustomAttributes(); /** * Sets the custom attribute Map of the attachment. @@ -111,7 +111,8 @@ public interface Attachment { * @param customAttributes * a {@link Map} that contains the custom attributes of the attachment as key, value pairs */ - void setCustomAttributes(Map customAttributes); + void setCustomAttributes(Map customAttributes); + /** * Return a summary of the current Attachment. * diff --git a/lib/taskana-core/src/main/java/pro/taskana/Task.java b/lib/taskana-core/src/main/java/pro/taskana/Task.java index 15803c97c..9e01b07e7 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/Task.java +++ b/lib/taskana-core/src/main/java/pro/taskana/Task.java @@ -220,7 +220,15 @@ public interface Task { * * @return customAttributes as {@link Map} */ - Map getCustomAttributes(); + Map getCustomAttributes(); + + /** + * Sets a collection of customAttributes. + * + * @param customAttributes + * a {@link Map} that contains the custom attributes + */ + void setCustomAttributes(Map customAttributes); /** * Return the value for the 1. customAttribute. diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentImpl.java index e08d44332..50b9e07cf 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentImpl.java @@ -24,7 +24,7 @@ public class AttachmentImpl implements Attachment { private ObjectReference objectReference; private String channel; private Instant received; - private Map customAttributes = Collections.emptyMap(); + private Map customAttributes = Collections.emptyMap(); AttachmentImpl() { } @@ -116,12 +116,12 @@ public class AttachmentImpl implements Attachment { } @Override - public Map getCustomAttributes() { + public Map getCustomAttributes() { return customAttributes; } @Override - public void setCustomAttributes(Map customAttributes) { + public void setCustomAttributes(Map customAttributes) { this.customAttributes = customAttributes; } diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java index 068cde610..99664457c 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java @@ -41,7 +41,7 @@ public class TaskImpl implements Task { private boolean isRead; private boolean isTransferred; // All objects have to be serializable - private Map customAttributes = Collections.emptyMap(); + private Map customAttributes = Collections.emptyMap(); private List attachments = new ArrayList<>(); private String custom1; private String custom2; @@ -294,11 +294,12 @@ public class TaskImpl implements Task { } @Override - public Map getCustomAttributes() { + public Map getCustomAttributes() { return customAttributes; } - public void setCustomAttributes(Map customAttributes) { + @Override + public void setCustomAttributes(Map customAttributes) { this.customAttributes = customAttributes; } diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/MapTypeHandler.java b/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/MapTypeHandler.java index 51ed0ef00..3c58bdef2 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/MapTypeHandler.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/persistence/MapTypeHandler.java @@ -1,12 +1,7 @@ package pro.taskana.impl.persistence; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.sql.Blob; import java.sql.CallableStatement; +import java.sql.Clob; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -15,6 +10,7 @@ import java.util.Map; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.JdbcType; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,15 +28,11 @@ public class MapTypeHandler extends BaseTypeHandler { public void setNonNullParameter(PreparedStatement ps, int i, Map parameter, JdbcType jdbcType) throws SQLException { if (parameter != null && parameter.size() > 0) { LOGGER.debug("Input-Map before serializing: ", parameter); - // Convert Map to byte array - try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream()) { - ObjectOutputStream out = new ObjectOutputStream(byteOut); - out.writeObject(parameter); - ps.setBlob(i, new ByteArrayInputStream(byteOut.toByteArray())); - out.close(); - } catch (IOException e) { - LOGGER.error("During serialization of 'customAttributes' an error occured: ", e); - } + // Convert Map to JSON string + JSONObject jsonObj = new JSONObject(parameter); + Clob content = ps.getConnection().createClob(); + content.setString(1, jsonObj.toString()); + ps.setClob(i, content); } else { ps.setNull(i, Types.BLOB); } @@ -48,49 +40,36 @@ public class MapTypeHandler extends BaseTypeHandler { @Override public Map getNullableResult(ResultSet rs, String columnName) throws SQLException { - Blob fieldValue = rs.getBlob(columnName); + Clob fieldValue = rs.getClob(columnName); if (fieldValue != null) { - // Parse byte array to Map - Map result = null; - try (ObjectInputStream in = new ObjectInputStream(fieldValue.getBinaryStream())) { - result = (Map) in.readObject(); - } catch (ClassNotFoundException | IOException e) { - LOGGER.error("During deserialization of 'customAttributes' an error occured: ", e); - } - return result; + return convertClobToMap(fieldValue); } return null; } @Override public Map getNullableResult(ResultSet rs, int columnIndex) throws SQLException { - Blob fieldValue = rs.getBlob(columnIndex); + Clob fieldValue = rs.getClob(columnIndex); if (fieldValue != null) { - // Parse byte array to Map - Map result = null; - try (ObjectInputStream in = new ObjectInputStream(fieldValue.getBinaryStream())) { - result = (Map) in.readObject(); - } catch (ClassNotFoundException | IOException e) { - LOGGER.error("During deserialization of 'customAttributes' an error occured: ", e); - } - return result; + return convertClobToMap(fieldValue); } return null; } @Override public Map getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { - Blob fieldValue = cs.getBlob(columnIndex); + Clob fieldValue = cs.getClob(columnIndex); if (fieldValue != null) { - // Parse byte array to Map - Map result = null; - try (ObjectInputStream in = new ObjectInputStream(fieldValue.getBinaryStream())) { - result = (Map) in.readObject(); - } catch (ClassNotFoundException | IOException e) { - LOGGER.error("During deserialization of 'customAttributes' an error occured: ", e); - } - return result; + return convertClobToMap(fieldValue); } return null; } + + private Map convertClobToMap(Clob fieldValue) throws SQLException { + String content = fieldValue.getSubString(1L, (int) fieldValue.length()); + JSONObject jsonObj = new JSONObject(content); + Map result = jsonObj.toMap(); + return result; + } + } diff --git a/lib/taskana-core/src/main/java/pro/taskana/mappings/AttachmentMapper.java b/lib/taskana-core/src/main/java/pro/taskana/mappings/AttachmentMapper.java index e80ba679d..e2b38ce6f 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/mappings/AttachmentMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/mappings/AttachmentMapper.java @@ -10,6 +10,7 @@ import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.type.ClobTypeHandler; import org.apache.ibatis.type.JdbcType; import pro.taskana.impl.AttachmentImpl; @@ -23,7 +24,7 @@ public interface AttachmentMapper { @Insert("INSERT INTO ATTACHMENT (ID, TASK_ID, CREATED, MODIFIED, CLASSIFICATION_KEY, CLASSIFICATION_ID, REF_COMPANY, REF_SYSTEM, REF_INSTANCE, REF_TYPE, REF_VALUE, CHANNEL, RECEIVED, CUSTOM_ATTRIBUTES) " + "VALUES (#{att.id}, #{att.taskId}, #{att.created}, #{att.modified}, #{att.classificationSummary.key}, #{att.classificationSummary.id}, #{att.objectReference.company}, #{att.objectReference.system}, #{att.objectReference.systemInstance}, " - + " #{att.objectReference.type}, #{att.objectReference.value}, #{att.channel}, #{att.received}, #{att.customAttributes,jdbcType=BLOB,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler} )") + + " #{att.objectReference.type}, #{att.objectReference.value}, #{att.channel}, #{att.received}, #{att.customAttributes,jdbcType=CLOB,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler} )") void insert(@Param("att") AttachmentImpl att); @Select("SELECT ID, TASK_ID, CREATED, MODIFIED, CLASSIFICATION_KEY, CLASSIFICATION_ID, REF_COMPANY, REF_SYSTEM, REF_INSTANCE, REF_TYPE, REF_VALUE, CHANNEL, RECEIVED, CUSTOM_ATTRIBUTES " @@ -43,7 +44,7 @@ public interface AttachmentMapper { @Result(property = "objectReference.value", column = "REF_VALUE"), @Result(property = "channel", column = "CHANNEL"), @Result(property = "received", column = "RECEIVED"), - @Result(property = "customAttributes", column = "CUSTOM_ATTRIBUTES", jdbcType = JdbcType.BLOB, + @Result(property = "customAttributes", column = "CUSTOM_ATTRIBUTES", jdbcType = JdbcType.CLOB, javaType = Map.class, typeHandler = MapTypeHandler.class) }) List findAttachmentsByTaskId(@Param("taskId") String taskId); @@ -65,7 +66,7 @@ public interface AttachmentMapper { @Result(property = "objectReference.value", column = "REF_VALUE"), @Result(property = "channel", column = "CHANNEL"), @Result(property = "received", column = "RECEIVED"), - @Result(property = "customAttributes", column = "CUSTOM_ATTRIBUTES", jdbcType = JdbcType.BLOB, + @Result(property = "customAttributes", column = "CUSTOM_ATTRIBUTES", jdbcType = JdbcType.CLOB, javaType = Map.class, typeHandler = MapTypeHandler.class) }) AttachmentImpl getAttachment(@Param("attachmentId") String attachmentId); @@ -93,7 +94,14 @@ public interface AttachmentMapper { @Update("UPDATE ATTACHMENT SET TASK_ID = #{taskId}, CREATED = #{created}, MODIFIED = #{modified}," + " CLASSIFICATION_KEY = #{classificationSummary.key}, CLASSIFICATION_ID = #{classificationSummary.id}, REF_COMPANY = #{objectReference.company}, REF_SYSTEM = #{objectReference.system}," + " REF_INSTANCE = #{objectReference.systemInstance}, REF_TYPE = #{objectReference.type}, REF_VALUE = #{objectReference.value}," - + " CHANNEL = #{channel}, RECEIVED = #{received}, CUSTOM_ATTRIBUTES = #{customAttributes,jdbcType=BLOB,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler}" + + " CHANNEL = #{channel}, RECEIVED = #{received}, CUSTOM_ATTRIBUTES = #{customAttributes,jdbcType=CLOB,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler}" + " WHERE ID = #{id}") void update(AttachmentImpl attachment); + + @Select("select CUSTOM_ATTRIBUTES from attachment where id = #{attachmentId}") + @Results(value = { + @Result(property = "customAttributes", column = "CUSTOM_ATTRIBUTES", jdbcType = JdbcType.CLOB, + javaType = String.class, typeHandler = ClobTypeHandler.class) + }) + String getCustomAttributesAsString(@Param("attachmentId") String attachmentId); } diff --git a/lib/taskana-core/src/main/java/pro/taskana/mappings/TaskMapper.java b/lib/taskana-core/src/main/java/pro/taskana/mappings/TaskMapper.java index 3447a1503..38d224def 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/mappings/TaskMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/mappings/TaskMapper.java @@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Result; import org.apache.ibatis.annotations.Results; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.type.ClobTypeHandler; import org.apache.ibatis.type.JdbcType; import pro.taskana.impl.MinimalTaskSummary; @@ -63,7 +64,7 @@ public interface TaskMapper { @Result(property = "primaryObjRef.value", column = "POR_VALUE"), @Result(property = "isRead", column = "IS_READ"), @Result(property = "isTransferred", column = "IS_TRANSFERRED"), - @Result(property = "customAttributes", column = "CUSTOM_ATTRIBUTES", jdbcType = JdbcType.BLOB, + @Result(property = "customAttributes", column = "CUSTOM_ATTRIBUTES", jdbcType = JdbcType.CLOB, javaType = Map.class, typeHandler = MapTypeHandler.class), @Result(property = "custom1", column = "CUSTOM_1"), @Result(property = "custom2", column = "CUSTOM_2"), @@ -83,7 +84,7 @@ public interface TaskMapper { + "VALUES(#{id}, #{created}, #{claimed}, #{completed}, #{modified}, #{planned}, #{due}, #{name}, #{creator}, #{description}, #{note}, #{priority}, #{state}, #{classificationSummary.category}, " + "#{classificationSummary.key}, #{classificationSummary.id}, #{workbasketSummary.id}, #{workbasketSummary.key}, #{workbasketSummary.domain}, #{businessProcessId}, " + "#{parentBusinessProcessId}, #{owner}, #{primaryObjRef.company}, #{primaryObjRef.system}, #{primaryObjRef.systemInstance}, #{primaryObjRef.type}, #{primaryObjRef.value}, " - + "#{isRead}, #{isTransferred}, #{customAttributes,jdbcType=BLOB,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler}, " + + "#{isRead}, #{isTransferred}, #{customAttributes,jdbcType=CLOB,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler}, " + "#{custom1}, #{custom2}, #{custom3}, #{custom4}, #{custom5}, #{custom6}, #{custom7}, #{custom8}, #{custom9}, #{custom10})") @Options(keyProperty = "id", keyColumn = "ID") void insert(TaskImpl task); @@ -93,7 +94,7 @@ public interface TaskMapper { + "WORKBASKET_ID = #{workbasketSummary.id}, WORKBASKET_KEY = #{workbasketSummary.key}, DOMAIN = #{workbasketSummary.domain}, " + "BUSINESS_PROCESS_ID = #{businessProcessId}, PARENT_BUSINESS_PROCESS_ID = #{parentBusinessProcessId}, OWNER = #{owner}, POR_COMPANY = #{primaryObjRef.company}, POR_SYSTEM = #{primaryObjRef.system}, " + "POR_INSTANCE = #{primaryObjRef.systemInstance}, POR_TYPE = #{primaryObjRef.type}, POR_VALUE = #{primaryObjRef.value}, IS_READ = #{isRead}, IS_TRANSFERRED = #{isTransferred}, " - + "CUSTOM_ATTRIBUTES = #{customAttributes,jdbcType=BLOB,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler}, CUSTOM_1 = #{custom1}, CUSTOM_2 = #{custom2}, " + + "CUSTOM_ATTRIBUTES = #{customAttributes,jdbcType=CLOB,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler}, CUSTOM_1 = #{custom1}, CUSTOM_2 = #{custom2}, " + "CUSTOM_3 = #{custom3}, CUSTOM_4 = #{custom4}, CUSTOM_5 = #{custom5}, CUSTOM_6 = #{custom6}, CUSTOM_7 = #{custom7}, CUSTOM_8 = #{custom8}, CUSTOM_9 = #{custom9}, CUSTOM_10 = #{custom10} " + "WHERE ID = #{id}") void update(TaskImpl task); @@ -223,4 +224,12 @@ public interface TaskMapper { + "") void updateClassificationCategoryOnChange(@Param("taskIds") List taskIds, @Param("newCategory") String newCategory); + + @Select("select CUSTOM_ATTRIBUTES from task where id = #{taskId}") + @Results(value = { + @Result(property = "customAttributes", column = "CUSTOM_ATTRIBUTES", jdbcType = JdbcType.CLOB, + javaType = String.class, typeHandler = ClobTypeHandler.class) + }) + String getCustomAttributesAsString(@Param("taskId") String taskId); + } diff --git a/lib/taskana-core/src/main/resources/sql/taskana-schema.sql b/lib/taskana-core/src/main/resources/sql/taskana-schema.sql index 6e886ffca..56ea63c9f 100644 --- a/lib/taskana-core/src/main/resources/sql/taskana-schema.sql +++ b/lib/taskana-core/src/main/resources/sql/taskana-schema.sql @@ -83,7 +83,7 @@ CREATE TABLE TASK ( POR_VALUE VARCHAR(128) NOT NULL, IS_READ BOOLEAN NOT NULL, IS_TRANSFERRED BOOLEAN NOT NULL, - CUSTOM_ATTRIBUTES BLOB NULL, + CUSTOM_ATTRIBUTES CLOB NULL, CUSTOM_1 VARCHAR(255) NULL, CUSTOM_2 VARCHAR(255) NULL, CUSTOM_3 VARCHAR(255) NULL, @@ -152,7 +152,7 @@ CREATE TABLE ATTACHMENT( REF_VALUE VARCHAR(128) NOT NULL, CHANNEL VARCHAR(64) NULL, RECEIVED TIMESTAMP NULL, - CUSTOM_ATTRIBUTES BLOB NULL, + CUSTOM_ATTRIBUTES CLOB NULL, PRIMARY KEY (ID), CONSTRAINT ATT_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION ); diff --git a/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java b/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java index 3882beae6..2d1e89392 100644 --- a/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/AbstractAccTest.java @@ -68,8 +68,8 @@ public abstract class AbstractAccTest { return objectReference; } - protected Map createSimpleCustomProperties(int propertiesCount) { - HashMap properties = new HashMap<>(); + protected Map createSimpleCustomProperties(int propertiesCount) { + HashMap properties = new HashMap<>(); for (int i = 1; i <= propertiesCount; i++) { properties.put("Property_" + i, "Property Value of Property_" + i); } @@ -77,7 +77,7 @@ public abstract class AbstractAccTest { } protected Attachment createAttachment(String classificationKey, ObjectReference objRef, - String channel, String receivedDate, Map customAttributes) + String channel, String receivedDate, Map customAttributes) throws ClassificationNotFoundException, NotAuthorizedException { Attachment attachment = taskanaEngine.getTaskService().newAttachment(); diff --git a/lib/taskana-core/src/test/java/acceptance/task/CreateTaskAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/CreateTaskAccTest.java index 7b57d885d..52eb98ba3 100644 --- a/lib/taskana-core/src/test/java/acceptance/task/CreateTaskAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/task/CreateTaskAccTest.java @@ -4,10 +4,13 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.sql.SQLException; +import java.util.Map; +import org.apache.ibatis.session.SqlSession; import org.h2.store.fs.FileUtils; import org.junit.AfterClass; import org.junit.Test; @@ -28,6 +31,10 @@ import pro.taskana.exceptions.TaskNotFoundException; import pro.taskana.exceptions.WorkbasketNotFoundException; import pro.taskana.impl.TaskState; import pro.taskana.security.CurrentUserContext; +import pro.taskana.impl.TaskanaEngineImpl; +import pro.taskana.impl.TaskanaEngineProxyForTest; +import pro.taskana.mappings.AttachmentMapper; +import pro.taskana.mappings.TaskMapper; import pro.taskana.security.JAASRunner; import pro.taskana.security.WithAccessId; @@ -73,6 +80,68 @@ public class CreateTaskAccTest extends AbstractAccTest { assertEquals(false, createdTask.isTransferred()); } + @WithAccessId( + userName = "user_1_1", + groupNames = {"group_1"}) + @Test + public void testCreateSimpleTaskWithCustomAttributes() + throws SQLException, NotAuthorizedException, InvalidArgumentException, ClassificationNotFoundException, + WorkbasketNotFoundException, TaskAlreadyExistException, InvalidWorkbasketException, TaskNotFoundException { + + TaskService taskService = taskanaEngine.getTaskService(); + Task newTask = taskService.newTask("USER_1_1", "DOMAIN_A"); + newTask.setClassificationKey("T2100"); + newTask.setPrimaryObjRef(createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567")); + Map customAttributesForCreate = createSimpleCustomProperties(13); + newTask.setCustomAttributes(customAttributesForCreate); + Task createdTask = taskService.createTask(newTask); + + assertNotNull(createdTask); + assertEquals("T-Vertragstermin VERA", createdTask.getName()); + assertEquals("1234567", createdTask.getPrimaryObjRef().getValue()); + assertNotNull(createdTask.getCreated()); + assertNotNull(createdTask.getModified()); + assertNotNull(createdTask.getBusinessProcessId()); + assertEquals(null, createdTask.getClaimed()); + assertEquals(null, createdTask.getCompleted()); + assertEquals(createdTask.getCreated(), createdTask.getModified()); + assertEquals(createdTask.getCreated(), createdTask.getPlanned()); + assertEquals(TaskState.READY, createdTask.getState()); + assertEquals(null, createdTask.getParentBusinessProcessId()); + assertEquals(2, createdTask.getPriority()); + assertEquals(false, createdTask.isRead()); + assertEquals(false, createdTask.isTransferred()); + // verify that the database content is as expected + TaskanaEngineProxyForTest engineProxy = new TaskanaEngineProxyForTest((TaskanaEngineImpl) taskanaEngine); + try { + SqlSession session = engineProxy.getSqlSession(); + TaskMapper mapper = session.getMapper(TaskMapper.class); + engineProxy.openConnection(); + String customProperties = mapper.getCustomAttributesAsString(createdTask.getId()); + assertTrue(customProperties.contains("\"Property_13\":\"Property Value of Property_13\"")); + assertTrue(customProperties.contains("\"Property_12\":\"Property Value of Property_12\"")); + assertTrue(customProperties.contains("\"Property_11\":\"Property Value of Property_11\"")); + assertTrue(customProperties.contains("\"Property_10\":\"Property Value of Property_10\"")); + assertTrue(customProperties.contains("\"Property_9\":\"Property Value of Property_9\"")); + assertTrue(customProperties.contains("\"Property_8\":\"Property Value of Property_8\"")); + assertTrue(customProperties.contains("\"Property_7\":\"Property Value of Property_7\"")); + assertTrue(customProperties.contains("\"Property_6\":\"Property Value of Property_6\"")); + assertTrue(customProperties.contains("\"Property_5\":\"Property Value of Property_5\"")); + assertTrue(customProperties.contains("\"Property_4\":\"Property Value of Property_4\"")); + assertTrue(customProperties.contains("\"Property_3\":\"Property Value of Property_3\"")); + assertTrue(customProperties.contains("\"Property_2\":\"Property Value of Property_2\"")); + assertTrue(customProperties.contains("\"Property_1\":\"Property Value of Property_1\"")); + } finally { + engineProxy.returnConnection(); + } + // verify that the map is correctly retrieved from the database + Task retrievedTask = taskService.getTask(createdTask.getId()); + Map customAttributesFromDb = retrievedTask.getCustomAttributes(); + assertNotNull(customAttributesFromDb); + assertTrue(customAttributesFromDb.equals(customAttributesForCreate)); + + } + @WithAccessId( userName = "user_1_1", groupNames = {"group_1"}) @@ -85,15 +154,36 @@ public class CreateTaskAccTest extends AbstractAccTest { TaskService taskService = taskanaEngine.getTaskService(); Task newTask = taskService.newTask("USER_1_1", "DOMAIN_A"); newTask.setClassificationKey("L12010"); + Map customAttributesForCreate = createSimpleCustomProperties(27); newTask.addAttachment(createAttachment("DOCTYPE_DEFAULT", createObjectReference("COMPANY_A", "SYSTEM_B", "INSTANCE_B", "ArchiveId", "12345678901234567890123456789012345678901234567890"), - "E-MAIL", "2018-01-15", createSimpleCustomProperties(3))); + "E-MAIL", "2018-01-15", customAttributesForCreate)); newTask.setPrimaryObjRef(createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567")); Task createdTask = taskService.createTask(newTask); assertNotNull(createdTask.getId()); assertThat(createdTask.getCreator(), equalTo(CurrentUserContext.getUserid())); + // verify that the database content is as expected + TaskanaEngineProxyForTest engineProxy = new TaskanaEngineProxyForTest((TaskanaEngineImpl) taskanaEngine); + try { + SqlSession session = engineProxy.getSqlSession(); + AttachmentMapper mapper = session.getMapper(AttachmentMapper.class); + engineProxy.openConnection(); + String customProperties = mapper.getCustomAttributesAsString(createdTask.getAttachments().get(0).getId()); + assertTrue(customProperties.contains("\"Property_26\":\"Property Value of Property_26\"")); + assertTrue(customProperties.contains("\"Property_25\":\"Property Value of Property_25\"")); + assertTrue(customProperties.contains("\"Property_21\":\"Property Value of Property_21\"")); + assertTrue(customProperties.contains("\"Property_19\":\"Property Value of Property_19\"")); + assertTrue(customProperties.contains("\"Property_16\":\"Property Value of Property_16\"")); + assertTrue(customProperties.contains("\"Property_12\":\"Property Value of Property_12\"")); + assertTrue(customProperties.contains("\"Property_11\":\"Property Value of Property_11\"")); + assertTrue(customProperties.contains("\"Property_7\":\"Property Value of Property_7\"")); + assertTrue(customProperties.contains("\"Property_6\":\"Property Value of Property_6\"")); + } finally { + engineProxy.returnConnection(); + } + Task readTask = taskService.getTask(createdTask.getId()); assertNotNull(readTask); assertThat(readTask.getCreator(), equalTo(CurrentUserContext.getUserid())); @@ -104,6 +194,10 @@ public class CreateTaskAccTest extends AbstractAccTest { assertEquals(readTask.getAttachments().get(0).getCreated(), readTask.getAttachments().get(0).getModified()); assertNotNull(readTask.getAttachments().get(0).getClassificationSummary()); assertNotNull(readTask.getAttachments().get(0).getObjectReference()); + // verify that the map is correctly retrieved from the database + Map customAttributesFromDb = readTask.getAttachments().get(0).getCustomAttributes(); + assertNotNull(customAttributesFromDb); + assertTrue(customAttributesFromDb.equals(customAttributesForCreate)); } @WithAccessId(