From 8165e0b756de5434add24e3bee45acecc094b06c Mon Sep 17 00:00:00 2001
From: alaskowski <alaskowski@ethz.ch>
Date: Thu, 21 Sep 2023 13:04:42 +0200
Subject: [PATCH] SSDM-55: Improved property converter for multi-value
 properties

---
 .../property/PropertyTranslator.java          | 102 +++++++++++-------
 .../dataaccess/EntityPropertiesConverter.java |  30 ++++--
 2 files changed, 89 insertions(+), 43 deletions(-)

diff --git a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyTranslator.java b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyTranslator.java
index bc908803a2b..f406a320fed 100644
--- a/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyTranslator.java
+++ b/server-application-server/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/translator/property/PropertyTranslator.java
@@ -55,66 +55,53 @@ public abstract class PropertyTranslator extends
                         records.stream().filter(r -> r.sample_id != null).map(r -> r.sample_id)
                                 .collect(Collectors.toSet()));
 
-        Map<Long, Map<String, Serializable>> properties = new HashMap<Long, Map<String, Serializable>>();
+        Map<Long, Map<String, Serializable>> properties =
+                new HashMap<Long, Map<String, Serializable>>();
         for (PropertyRecord record : records)
         {
             Map<String, Serializable> objectProperties = properties.get(record.objectId);
 
             if (objectProperties == null)
             {
-                objectProperties = new HashMap<String, Serializable>();
+                objectProperties = new HashMap<>();
                 properties.put(record.objectId, objectProperties);
             }
 
             if (record.propertyValue != null)
             {
-                objectProperties.put(record.propertyCode, record.propertyValue);
+                updateObjectProperty(objectProperties, record.propertyCode, record.propertyValue);
             } else if (record.materialPropertyValueCode != null)
             {
-                objectProperties.put(record.propertyCode,
+                updateObjectProperty(objectProperties, record.propertyCode,
                         record.materialPropertyValueCode + " (" + record.materialPropertyValueTypeCode
                                 + ")");
             } else if (record.vocabularyPropertyValue != null)
             {
-                if(objectProperties.containsKey(record.propertyCode)) {
-                    Serializable current = objectProperties.get(record.propertyCode);
-                    Serializable newValue = composeMultiValueProperty(current, record.vocabularyPropertyValue);
-                    objectProperties.put(record.propertyCode, newValue);
-                } else {
-                    objectProperties.put(record.propertyCode, record.vocabularyPropertyValue);
-                }
+                updateObjectProperty(objectProperties, record.propertyCode,
+                        record.vocabularyPropertyValue);
             } else if (record.sample_perm_id != null)
             {
-                if (visibaleSamples.contains(record.sample_id))
-                {
-                    if(objectProperties.containsKey(record.propertyCode)) {
-                        Serializable current = objectProperties.get(record.propertyCode);
-                        Serializable newValue = composeMultiValueProperty(current, record.sample_perm_id);
-                        objectProperties.put(record.propertyCode, newValue);
-                    } else
-                    {
-                        objectProperties.put(record.propertyCode, record.sample_perm_id);
-                    }
-                }
+                updateObjectProperty(objectProperties, record.propertyCode, record.sample_perm_id);
             } else if (record.integerArrayPropertyValue != null)
             {
-                objectProperties.put(record.propertyCode,
-                        convertArrayToString(record.integerArrayPropertyValue));
+                updateArrayObjectProperty(objectProperties, record.propertyCode,
+                        record.integerArrayPropertyValue);
             } else if (record.realArrayPropertyValue != null)
             {
-                objectProperties.put(record.propertyCode,
-                        convertArrayToString(record.realArrayPropertyValue));
+                updateArrayObjectProperty(objectProperties, record.propertyCode,
+                        record.realArrayPropertyValue);
             } else if (record.stringArrayPropertyValue != null)
             {
-                objectProperties.put(record.propertyCode,
-                        convertArrayToString(record.stringArrayPropertyValue));
+                updateArrayObjectProperty(objectProperties, record.propertyCode,
+                        record.stringArrayPropertyValue);
             } else if (record.timestampArrayPropertyValue != null)
             {
-                objectProperties.put(record.propertyCode,
-                        convertArrayToString(record.timestampArrayPropertyValue));
+                updateArrayObjectProperty(objectProperties, record.propertyCode,
+                        record.timestampArrayPropertyValue);
             } else if (record.jsonPropertyValue != null)
             {
-                objectProperties.put(record.propertyCode, record.jsonPropertyValue);
+                updateObjectProperty(objectProperties, record.propertyCode,
+                        record.jsonPropertyValue);
             } else
             {
                 // SAMPLE property with deleted sample. Thus, nothing is put to objectProperties
@@ -124,15 +111,57 @@ public abstract class PropertyTranslator extends
         return properties;
     }
 
-    private Serializable composeMultiValueProperty(Serializable current, Serializable newValue) {
+    private void updateObjectProperty(Map<String, Serializable> objectProperties,
+            String propertyCode, Serializable propertyValue)
+    {
+        if (objectProperties.containsKey(propertyCode))
+        {
+            Serializable current = objectProperties.get(propertyCode);
+            Serializable newValue = composeMultiValueProperty(current, propertyValue);
+            objectProperties.put(propertyCode, newValue);
+        } else
+        {
+            objectProperties.put(propertyCode, propertyValue);
+        }
+    }
+
+    private void updateArrayObjectProperty(Map<String, Serializable> objectProperties,
+            String propertyCode, Serializable[] propertyValue)
+    {
+        if (objectProperties.containsKey(propertyCode))
+        {
+            Serializable[] current = (Serializable[]) objectProperties.get(propertyCode);
+            Serializable[] result;
+            if(current.length > 0) {
+                if(current[0].getClass().isArray()) {
+                    result = new Serializable[current.length + 1];
+                    System.arraycopy(current, 0, result, 0, current.length);
+                    result[current.length] = propertyValue;
+                } else {
+                    result = new Serializable[] {current, propertyValue};
+                }
+            } else {
+                result = propertyValue;
+            }
+            objectProperties.put(propertyCode, result);
+        } else
+        {
+            objectProperties.put(propertyCode, propertyValue);
+        }
+    }
+
+    private Serializable composeMultiValueProperty(Serializable current, Serializable newValue)
+    {
         Serializable[] result;
-        if(current.getClass().isArray()) {
+        if (current.getClass().isArray())
+        {
             Serializable[] values = (Serializable[]) current;
             result = new Serializable[values.length + 1];
             System.arraycopy(values, 0, result, 0, values.length);
             result[values.length] = newValue;
-        } else {
-            result = new Serializable[] {current, newValue};
+        } else
+        {
+            result = new Serializable[] { current, newValue };
         }
         return result;
     }
@@ -150,7 +179,8 @@ public abstract class PropertyTranslator extends
             ObjectHolder<Map<String, Serializable>> result, Object relations,
             PropertyFetchOptions fetchOptions)
     {
-        Map<Long, Map<String, Serializable>> properties = (Map<Long, Map<String, Serializable>>) relations;
+        Map<Long, Map<String, Serializable>> properties =
+                (Map<Long, Map<String, Serializable>>) relations;
         Map<String, Serializable> objectProperties = properties.get(objectId);
 
         if (objectProperties == null)
diff --git a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/EntityPropertiesConverter.java b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/EntityPropertiesConverter.java
index a08157c3f3c..d8fdb2ef294 100644
--- a/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/EntityPropertiesConverter.java
+++ b/server-application-server/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/EntityPropertiesConverter.java
@@ -268,7 +268,7 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
     {
         final String propertyCode = property.getPropertyType().getCode();
         final PropertyTypePE propertyType = getPropertyType(propertyCode);
-        final String valueOrNull = property.tryGetAsString();
+        final Serializable valueOrNull = property.getValue();
         ExtendedEntityTypePropertyType extendedETPT =
                 getEntityTypePropertyType(entityTypePE, propertyType);
         final EntityTypePropertyTypePE entityTypePropertyTypePE =
@@ -281,12 +281,26 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
         if (isNullOrBlank(valueOrNull) == false)
         {
             List<T> results = new ArrayList<>();
-            String translatedValue = extendedETPT.translate(registrator, valueOrNull);
+            if(propertyType.isMultiValue() && valueOrNull.getClass().isArray()) {
+                for (Serializable value : (Serializable[]) valueOrNull)
+                {
+                    String translatedValue =
+                            extendedETPT.translate(registrator, (String) value);
+                    final String validatedValue =
+                            propertyValueValidator.validatePropertyValue(propertyType,
+                                    translatedValue);
+                    results.addAll(createEntityProperty(registrator, propertyType,
+                            entityTypePropertyTypePE,
+                            validatedValue));
+                }
+            } else {
+                String translatedValue = extendedETPT.translate(registrator, (String) valueOrNull);
 
-            final String validatedValue =
-                    propertyValueValidator.validatePropertyValue(propertyType, translatedValue);
-            results.addAll(createEntityProperty(registrator, propertyType, entityTypePropertyTypePE,
-                    validatedValue));
+                final String validatedValue =
+                        propertyValueValidator.validatePropertyValue(propertyType, translatedValue);
+                results.addAll(createEntityProperty(registrator, propertyType, entityTypePropertyTypePE,
+                        validatedValue));
+            }
             return results;
         }
         return null;
@@ -299,7 +313,9 @@ public final class EntityPropertiesConverter implements IEntityPropertiesConvert
     {
         List<T> entityProperties = new ArrayList<>();
         String val = value;
-        if (propertyType.isMultiValue())
+        List<DataTypeCode> arrayTypes = List.of(DataTypeCode.ARRAY_STRING,
+                DataTypeCode.ARRAY_INTEGER, DataTypeCode.ARRAY_REAL, DataTypeCode.ARRAY_TIMESTAMP);
+        if (propertyType.isMultiValue() && !arrayTypes.contains(propertyType.getType().getCode()))
         {
             if (val.startsWith("["))
             {
-- 
GitLab