From 1f1684f4c5ea138160299fc37f0151a8985eefb3 Mon Sep 17 00:00:00 2001
From: tpylak <tpylak>
Date: Wed, 31 Aug 2011 14:12:25 +0000
Subject: [PATCH] LMS-2460 fix: allow to update contained samples

SVN: 22747
---
 .../bo/AbstractSampleBusinessObject.java      |  12 +--
 .../generic/shared/basic/dto/NewSample.java   |  29 +++--
 .../shared/basic/dto/UpdatedSample.java       |   2 +-
 .../dto/identifier/SampleIdentifier.java      |   2 +-
 .../identifier/SampleIdentifierFactory.java   |  16 +++
 .../plugin/generic/server/GenericServer.java  |  22 ++--
 .../server/SampleRegisterOrUpdateUtil.java    | 102 +++++++++++++++---
 .../generic/server/GenericServerTest.java     |   2 +-
 8 files changed, 144 insertions(+), 43 deletions(-)

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
index 14faaa33fbe..236de30a602 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/AbstractSampleBusinessObject.java
@@ -109,9 +109,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
             Map<String, ExperimentPE> experimentCacheOrNull, PersonPE registratorOrNull)
             throws UserFailureException
     {
-        final SampleIdentifier sampleIdentifier =
-                SampleIdentifierFactory.parse(newSample.getIdentifier(),
-                        newSample.getSpaceIdentifier());
+        final SampleIdentifier sampleIdentifier = SampleIdentifierFactory.parse(newSample);
         SampleOwner sampleOwner = getSampleOwner(sampleOwnerCacheOrNull, sampleIdentifier);
         SampleTypePE sampleTypePE =
                 (sampleTypeCacheOrNull != null) ? sampleTypeCacheOrNull.get(newSample
@@ -127,7 +125,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
         String experimentIdentifier = newSample.getExperimentIdentifier();
         ExperimentPE experimentPE =
                 tryFindExperiment(experimentCacheOrNull, experimentIdentifier,
-                        newSample.getSpaceIdentifier());
+                        newSample.getDefaultSpaceIdentifier());
         final SamplePE samplePE = new SamplePE();
         samplePE.setExperiment(experimentPE);
         samplePE.setCode(sampleIdentifier.getSampleSubCode());
@@ -139,11 +137,11 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
         defineSampleProperties(samplePE, newSample.getProperties());
         String containerIdentifier = newSample.getContainerIdentifier();
         setContainer(sampleIdentifier, samplePE, containerIdentifier,
-                newSample.getSpaceIdentifier());
+                newSample.getDefaultSpaceIdentifier());
         if (newSample.getParentsOrNull() != null)
         {
             final String[] parents = newSample.getParentsOrNull();
-            setParents(samplePE, parents, newSample.getSpaceIdentifier());
+            setParents(samplePE, parents, newSample.getDefaultSpaceIdentifier());
         }
         samplePE.setPermId(getOrCreatePermID(newSample));
         return samplePE;
@@ -575,7 +573,7 @@ abstract class AbstractSampleBusinessObject extends AbstractSampleIdentifierBusi
         for (SampleIdentifier sampleIdentifier : sampleIdentifiers)
         {
             final SampleOwner sampleOwner = getSampleOwner(sampleOwnerCache, sampleIdentifier);
-            final String containerCodeOrNull = sampleIdentifier.getContainerCodeOrNull();
+            final String containerCodeOrNull = sampleIdentifier.tryGetContainerCode();
             final SampleOwnerWithContainer owner =
                     new SampleOwnerWithContainer(sampleOwner, containerCodeOrNull);
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/NewSample.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/NewSample.java
index 62eb75fc78f..395f4793293 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/NewSample.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/NewSample.java
@@ -45,6 +45,8 @@ public class NewSample extends Identifier<NewSample> implements Comparable<NewSa
 
     public static final String CONTAINER = "container";
 
+    public static final String DEFAULT_CONTAINER = "default_container";
+
     public static final String PARENT = "parent";
 
     public static final String PARENTS = "parents";
@@ -74,7 +76,7 @@ public class NewSample extends Identifier<NewSample> implements Comparable<NewSa
     /***
      * The space code for this row home space
      */
-    private String spaceIdentifier;
+    private String defaultSpaceIdentifier;
 
     private IEntityProperty[] properties = IEntityProperty.EMPTY_ARRAY;
 
@@ -115,7 +117,7 @@ public class NewSample extends Identifier<NewSample> implements Comparable<NewSa
         this(identifier, sampleType, containerIdentifier);
         this.parentsOrNull = parentsOrNull;
         this.experimentIdentifier = experimentIdentifier;
-        this.spaceIdentifier = spaceCode;
+        this.defaultSpaceIdentifier = spaceCode;
         this.properties = properties;
         this.attachments = attachments;
     }
@@ -202,6 +204,17 @@ public class NewSample extends Identifier<NewSample> implements Comparable<NewSa
         this.containerIdentifier = container;
     }
 
+    public final String getDefaultContainerIdentifier()
+    {
+        return containerIdentifier;
+    }
+
+    @BeanProperty(label = DEFAULT_CONTAINER, optional = true)
+    public final void setDefaultContainerIdentifier(final String defaultContainer)
+    {
+        this.containerIdentifier = defaultContainer;
+    }
+
     public String getExperimentIdentifier()
     {
         return experimentIdentifier;
@@ -213,15 +226,15 @@ public class NewSample extends Identifier<NewSample> implements Comparable<NewSa
         this.experimentIdentifier = experimentIdentifier;
     }
 
-    public String getSpaceIdentifier()
+    public String getDefaultSpaceIdentifier()
     {
-        return spaceIdentifier;
+        return defaultSpaceIdentifier;
     }
 
     @BeanProperty(label = SPACE, optional = true)
-    public void setSpaceIdentifier(String spaceIdentifier)
+    public void setDefaultSpaceIdentifier(String spaceIdentifier)
     {
-        this.spaceIdentifier = spaceIdentifier;
+        this.defaultSpaceIdentifier = spaceIdentifier;
     }
 
     public final IEntityProperty[] getProperties()
@@ -269,10 +282,10 @@ public class NewSample extends Identifier<NewSample> implements Comparable<NewSa
         }
         final NewSample that = (NewSample) obj;
         final String thisCombinedIdentifier =
-                StringUtils.emptyIfNull(this.getSpaceIdentifier()) + this.getIdentifier()
+                StringUtils.emptyIfNull(this.getDefaultSpaceIdentifier()) + this.getIdentifier()
                         + this.getContainerIdentifier();
         final String thatCombinedIdentifier =
-                StringUtils.emptyIfNull(this.getSpaceIdentifier()) + that.getIdentifier()
+                StringUtils.emptyIfNull(this.getDefaultSpaceIdentifier()) + that.getIdentifier()
                         + that.getContainerIdentifier();
         return thisCombinedIdentifier.equals(thatCombinedIdentifier);
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/UpdatedSample.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/UpdatedSample.java
index ac3c3dc3fdc..747daae8e9b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/UpdatedSample.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/UpdatedSample.java
@@ -43,7 +43,7 @@ public final class UpdatedSample extends NewSample
     {
         super(newSample.getIdentifier(), newSample.getSampleType(), newSample
                 .getContainerIdentifier(), newSample.getParentsOrNull(), newSample
-                .getExperimentIdentifier(), newSample.getSpaceIdentifier(), newSample
+                .getExperimentIdentifier(), newSample.getDefaultSpaceIdentifier(), newSample
                 .getProperties(), newSample.getAttachments());
         this.batchUpdateDetails = batchUpdateDetails;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifier.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifier.java
index e4913fb6358..60ffc9aae96 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifier.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifier.java
@@ -96,7 +96,7 @@ public class SampleIdentifier extends SampleOwnerIdentifier
         return sampleSubCode;
     }
 
-    public String getContainerCodeOrNull()
+    public String tryGetContainerCode()
     {
         return containerCodeOrNull;
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifierFactory.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifierFactory.java
index 92cfe0ee2e1..f9061855806 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifierFactory.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/identifier/SampleIdentifierFactory.java
@@ -21,6 +21,7 @@ import static ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdent
 import org.apache.commons.lang.ArrayUtils;
 
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier.Constants;
 
 /**
@@ -41,6 +42,21 @@ public final class SampleIdentifierFactory extends AbstractIdentifierFactory
         return new SampleIdentifierFactory(textToParse).createIdentifier(null);
     }
 
+    public static final SampleIdentifier parse(final NewSample sample) throws UserFailureException
+    {
+        SampleIdentifierFactory factory = new SampleIdentifierFactory(sample.getIdentifier());
+        String defaultSpace = sample.getDefaultSpaceIdentifier();
+        SampleIdentifier identifier = factory.createIdentifier(defaultSpace);
+        // if the container for the new sample is not specified then use the default (if provided)
+        String defaultContainer = sample.getDefaultContainerIdentifier();
+        if (identifier.tryGetContainerCode() == null && defaultContainer != null)
+        {
+            SampleIdentifier defaultContainerIdentifier = parse(defaultContainer, defaultSpace);
+            identifier.addContainerCode(defaultContainerIdentifier.getSampleSubCode());
+        }
+        return identifier;
+    }
+
     public static final SampleIdentifier parse(final String textToParse, final String defaultSpace)
             throws UserFailureException
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
index 7d62578ab4c..4b886955904 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServer.java
@@ -293,15 +293,20 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
             updateSamples(session, new NewSamplesWithTypes(sampleType, samplesToUpdate));
         }
 
+        // TODO 2011-08-31, Tomasz Pylak: remove existing hacks
+        // 1. replaces contained samples with their containers if the container is
+        // specified in the contained sample identifier. This should be replaced by a flag not to
+        // update contained samples when the siRNA library is uploaded.
+        // 2. matches samples only by the code, so it can return match more samples if the sample
+        // with the same code exists in a different space. It does not hurt later on (matching is
+        // done by the identifier and additional samples are ignored), but is inefficient.
         private List<Sample> fetchExistingSamples(List<NewSample> newSamples)
         {
             List<Sample> existingSamples = new ArrayList<Sample>();
 
             // add non-contained samples codes
             List<String> codes = SampleRegisterOrUpdateUtil.extractCodes(newSamples, false);
-            // NOTE 2011-08-17, Tomasz Pylak: this code never updates contained samples,
-            // they can be only registered (if they did not exist).
-            // So only containers can be updated.
+            // NOTE 2011-08-17, Tomasz Pylak: this code never updates contained samples!
             List<Sample> list =
                     sampleLister.list(SampleRegisterOrUpdateUtil
                             .createListSamplesByCodeCriteria(codes));
@@ -420,8 +425,7 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
         for (NewSample updatedSample : updatedSamples)
         {
             final SampleIdentifier oldSampleIdentifier =
-                    SampleIdentifierFactory.parse(updatedSample.getIdentifier(),
-                            updatedSample.getSpaceIdentifier());
+                    SampleIdentifierFactory.parse(updatedSample);
             final List<IEntityProperty> properties = Arrays.asList(updatedSample.getProperties());
             final ExperimentIdentifier experimentIdentifierOrNull;
             final SampleIdentifier newSampleIdentifier;
@@ -430,7 +434,8 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
                 // experiment is provided - new sample identifier takes experiment space
                 experimentIdentifierOrNull =
                         new ExperimentIdentifierFactory(updatedSample.getExperimentIdentifier())
-                                .createIdentifier(updatedSample.getSpaceIdentifier());
+                                .createIdentifier(updatedSample.getDefaultSpaceIdentifier());
+                // TODO 2011-08-31, Tomasz Pylak: container is ignored, what does it break? 
                 newSampleIdentifier =
                         new SampleIdentifier(new GroupIdentifier(
                                 experimentIdentifierOrNull.getDatabaseInstanceCode(),
@@ -447,7 +452,7 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
             final SampleBatchUpdateDetails batchUpdateDetails =
                     createBatchUpdateDetails(updatedSample);
 
-            samples.add(new SampleBatchUpdatesDTO(updatedSample.getSpaceIdentifier(),
+            samples.add(new SampleBatchUpdatesDTO(updatedSample.getDefaultSpaceIdentifier(),
                     oldSampleIdentifier, properties, experimentIdentifierOrNull,
                     newSampleIdentifier, containerIdentifierOrNull, parentsOrNull,
                     batchUpdateDetails));
@@ -500,7 +505,8 @@ public final class GenericServer extends AbstractServer<IGenericServer> implemen
                 List<NewSample> newEntities = newSamplesWithType.getNewEntities();
                 for (NewSample newSample : newEntities)
                 {
-                    newSample.setSpaceIdentifier(new SpaceIdentifier(experimentSpace).toString());
+                    newSample.setDefaultSpaceIdentifier(new SpaceIdentifier(experimentSpace)
+                            .toString());
                 }
             }
             registerSamples(sessionToken, newSamples);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/SampleRegisterOrUpdateUtil.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/SampleRegisterOrUpdateUtil.java
index 2f2429abc41..77ee89295f4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/SampleRegisterOrUpdateUtil.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/SampleRegisterOrUpdateUtil.java
@@ -25,6 +25,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifierFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
 
 /**
  * Utility class for sample update or registration.
@@ -47,7 +48,7 @@ public class SampleRegisterOrUpdateUtil
         {
             for (Sample es : existingSamples)
             {
-                if (isMatching(ns.getIdentifier(), es.getIdentifier()))
+                if (isMatching(ns, es))
                 {
                     samplesToUpdate.add(ns);
                 }
@@ -56,33 +57,100 @@ public class SampleRegisterOrUpdateUtil
         return samplesToUpdate;
     }
 
-    /**
-     * Creates {@link ListOrSearchSampleCriteria} narrowing listing result to samples given codes.
-     */
-    static ListOrSearchSampleCriteria createListSamplesByCodeCriteria(List<String> codes)
+    private static boolean isMatching(NewSample newSample, Sample existingSample)
     {
-        String[] codesAsArray = codes.toArray(new String[0]);
-        ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(codesAsArray, false);
-        return criteria;
+        SampleIdentifier newSampleIdentifier = SampleIdentifierFactory.parse(newSample);
+        if (isMatchingIgnoringContainer(existingSample, newSampleIdentifier) == false)
+        {
+            return false;
+        }
+
+        // is container matching?
+        SampleIdentifier containerIdentifier =
+                tryCreateContainerIdentifier(newSample, newSampleIdentifier);
+        Sample containerSample = existingSample.getContainer();
+        return isMatchingIgnoringContainer(containerSample, containerIdentifier);
     }
 
-    /**
-     * Checks if given identifiers are matching (db instance is not considered).
-     */
-    private static boolean isMatching(String i1, String i2)
+    private static SampleIdentifier tryCreateContainerIdentifier(NewSample newSample,
+            SampleIdentifier newSampleIdentifier)
     {
-        if (i1 != null && i2 != null)
+        String newSampleContainerCode = newSampleIdentifier.tryGetContainerCode();
+        String newSampleContainerSpace = newSample.getDefaultSpaceIdentifier();
+        if (newSampleContainerCode == null && newSample.getContainerIdentifier() != null)
         {
-            return normalize(i1).equals(normalize(i2));
+            SampleIdentifier newSampleContainerIdentifier =
+                    SampleIdentifierFactory.parse(newSample.getContainerIdentifier(),
+                            newSample.getDefaultSpaceIdentifier());
+            newSampleContainerCode = newSampleContainerIdentifier.getSampleSubCode();
+            newSampleContainerSpace = tryGetSpaceCode(newSampleContainerIdentifier);
+        }
+        if (newSampleContainerCode == null)
+        {
+            return null;
         } else
         {
-            return i1 == i2;
+            return new SampleIdentifier(new SpaceIdentifier(newSampleContainerSpace),
+                    newSampleContainerCode);
         }
     }
 
-    private static String normalize(String id)
+    private static boolean isMatchingIgnoringContainer(Sample existingSample,
+            SampleIdentifier newSampleIdentifier)
     {
-        return dropDatabaseInstance(id).toUpperCase();
+        if (newSampleIdentifier == null || existingSample == null)
+        {
+            if (newSampleIdentifier != null || existingSample != null)
+            {
+                return false; // only one is null
+            }
+        }
+        if (existingSample == null)
+        {
+            assert newSampleIdentifier == null : "newSampleIdentifier is not null";
+            return true;
+        }
+        assert newSampleIdentifier != null : "newSampleIdentifier is null";
+
+        String newSampleSpace = tryGetSpaceCode(newSampleIdentifier);
+        String existingSampleSpace = existingSample.getSpace().getCode();
+        if (existingSampleSpace.equalsIgnoreCase(newSampleSpace) == false)
+        {
+            return false;
+        }
+
+        String newSampleSubCode = newSampleIdentifier.getSampleSubCode();
+        if (existingSample.getSubCode().equalsIgnoreCase(newSampleSubCode) == false)
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private static String tryGetSpaceCode(SampleIdentifier sampleIdentifier)
+    {
+        if (sampleIdentifier.isSpaceLevel())
+        {
+            String space = sampleIdentifier.getSpaceLevel().getSpaceCode();
+            if (space.startsWith(INSTANCE_SEPARATOR))
+            {
+                space = space.substring(1);
+            }
+            return space;
+        } else
+        {
+            return null;
+        }
+    }
+
+    /**
+     * Creates {@link ListOrSearchSampleCriteria} narrowing listing result to samples given codes.
+     */
+    static ListOrSearchSampleCriteria createListSamplesByCodeCriteria(List<String> codes)
+    {
+        String[] codesAsArray = codes.toArray(new String[0]);
+        ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(codesAsArray, false);
+        return criteria;
     }
 
     private static String dropDatabaseInstance(String id)
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerTest.java
index db19c5748b4..1bacf4e7439 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericServerTest.java
@@ -493,7 +493,7 @@ public final class GenericServerTest extends AbstractServerTestCase
         createServer().registerExperiment(SESSION_TOKEN, newExperiment,
                 Collections.<NewAttachment> emptyList());
         
-        assertEquals("/" + spaceCode, newSample1.getSpaceIdentifier());
+        assertEquals("/" + spaceCode, newSample1.getDefaultSpaceIdentifier());
         context.assertIsSatisfied();
     }
     
-- 
GitLab