diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractCreateEntityExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractCreateEntityExecutor.java index 0f5ac230711d4ca865759b0162409900d6ef4eb5..3bacc39271b96ab4310c06dcbf8e764f68bf3a95 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractCreateEntityExecutor.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractCreateEntityExecutor.java @@ -63,11 +63,12 @@ public abstract class AbstractCreateEntityExecutor<CREATION, PE, PERM_ID> implem context.popProgress(); } + daoFactory.getSessionFactory().getCurrentSession().flush(); reloadEntities(context, entitiesAll); updateAll(context, entitiesAll); + daoFactory.getSessionFactory().getCurrentSession().flush(); - reloadEntities(context, entitiesAll); checkBusinessRules(context, entitiesAll.values()); diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ListSampleTechIdByIdentifier.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ListSampleTechIdByIdentifier.java index 006c6d5afb261baaf386619f51df5f5d4af34e9e..80a1bf0c78f5df7cba3a0a21385bce1fc1f1ca14 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ListSampleTechIdByIdentifier.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ListSampleTechIdByIdentifier.java @@ -16,27 +16,30 @@ package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.sample; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import net.lemnik.eodsql.QueryTool; import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier; import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.TechIdStringIdentifierRecord; import ch.ethz.sis.openbis.generic.server.asapi.v3.helper.common.AbstractListTechIdById; +import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel; /** - * - * * @author Franz-Josef Elmer */ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleIdentifier> { - private String homeSpaceCodeOrNull; - + private String homeSpaceCodeOrNull; + public ListSampleTechIdByIdentifier(String homeSpaceCodeOrNull) { this.homeSpaceCodeOrNull = homeSpaceCodeOrNull; @@ -47,12 +50,12 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI { return SampleIdentifier.class; } - + @Override protected Map<Long, SampleIdentifier> createIdsByTechIdsMap(List<SampleIdentifier> ids) { Map<SampleIdentifierParts, Map<String, SampleIdentifier>> groupedIdentifiers = groupIdentifiers(ids); - + Map<Long, SampleIdentifier> result = new HashMap<>(); SampleQuery query = QueryTool.getManagedQuery(SampleQuery.class); for (Entry<SampleIdentifierParts, Map<String, SampleIdentifier>> entry : groupedIdentifiers.entrySet()) @@ -74,9 +77,9 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI Map<SampleIdentifierParts, Map<String, SampleIdentifier>> groupedIdentifiers = new HashMap<>(); for (SampleIdentifier sampleIdentifier : ids) { - FullSampleIdentifier fullSampleIdentifier = new FullSampleIdentifier(sampleIdentifier.getIdentifier(), + FullSampleIdentifier fullSampleIdentifier = new FullSampleIdentifier(sampleIdentifier.getIdentifier(), homeSpaceCodeOrNull); - + SampleIdentifierParts key = fullSampleIdentifier.getParts(); Map<String, SampleIdentifier> identifiersByCode = groupedIdentifiers.get(key); if (identifiersByCode == null) @@ -89,17 +92,32 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI return groupedIdentifiers; } - private List<TechIdStringIdentifierRecord> list(SampleQuery query, SampleIdentifierParts key, Collection<String> codes) + private List<TechIdStringIdentifierRecord> list(final SampleQuery query, final SampleIdentifierParts key, final Collection<String> codes) { - String[] codesArray = codes.toArray(new String[codes.size()]); - String spaceCode = key.getSpaceCodeOrNull(); - String projectCode = key.getProjectCodeOrNull(); - String containerCode = key.getContainerCodeOrNull(); + final String[] codesArray = codes.toArray(new String[codes.size()]); + final String spaceCode = key.getSpaceCodeOrNull(); + final String projectCode = key.getProjectCodeOrNull(); + final String containerCode = key.getContainerCodeOrNull(); + if (spaceCode == null) { if (containerCode == null) { - return query.listSharedSampleTechIdsByCodes(codesArray); + return listWithoutContainerOrWithSomeContainerAndUniqueCode(query, codesArray, new IListAction() + { + @Override + public List<TechIdStringIdentifierRecord> list(String[] codesToList) + { + return query.listSharedSampleTechIdsByCodesWithoutContainer(codesToList); + } + }, new IListAction() + { + @Override + public List<TechIdStringIdentifierRecord> list(String[] codesToList) + { + return query.listSharedSampleTechIdsByCodesWithSomeContainer(codesToList); + } + }); } return query.listSharedSampleTechIdsByContainerCodeAndCodes(containerCode, codesArray); } @@ -107,15 +125,98 @@ public class ListSampleTechIdByIdentifier extends AbstractListTechIdById<SampleI { if (containerCode == null) { - return query.listSpaceSampleTechIdsByCodes(spaceCode, codesArray); + return listWithoutContainerOrWithSomeContainerAndUniqueCode(query, codesArray, new IListAction() + { + @Override + public List<TechIdStringIdentifierRecord> list(String[] codesToList) + { + return query.listSpaceSampleTechIdsByCodesWithoutContainer(spaceCode, codesToList); + } + }, new IListAction() + { + @Override + public List<TechIdStringIdentifierRecord> list(String[] codesToList) + { + return query.listSpaceSampleTechIdsByCodesWithSomeContainer(spaceCode, codesToList); + } + }); } return query.listSpaceSampleTechIdsByContainerCodeAndCodes(spaceCode, containerCode, codesArray); } if (containerCode == null) { - return query.listProjectSampleTechIdsByCodes(spaceCode, projectCode, codesArray); + return listWithoutContainerOrWithSomeContainerAndUniqueCode(query, codesArray, new IListAction() + { + @Override + public List<TechIdStringIdentifierRecord> list(String[] codesToList) + { + return query.listProjectSampleTechIdsByCodesWithoutContainer(spaceCode, projectCode, codesToList); + } + }, new IListAction() + { + @Override + public List<TechIdStringIdentifierRecord> list(String[] codesToList) + { + return query.listProjectSampleTechIdsByCodesWithSomeContainer(spaceCode, projectCode, codesToList); + } + }); } return query.listProjectSampleTechIdsByContainerCodeAndCodes(spaceCode, projectCode, containerCode, codesArray); } + private List<TechIdStringIdentifierRecord> listWithoutContainerOrWithSomeContainerAndUniqueCode(SampleQuery query, String[] codes, + IListAction listWithoutContainer, IListAction listWithSomeContainer) + { + try + { + List<TechIdStringIdentifierRecord> foundWithoutContainer = listWithoutContainer.list(codes); + + Set<String> codesNotFound = new HashSet<String>(Arrays.asList(codes)); + for (TechIdStringIdentifierRecord found : foundWithoutContainer) + { + codesNotFound.remove(found.identifier); + } + + if (codesNotFound.isEmpty()) + { + return foundWithoutContainer; + } + + List<TechIdStringIdentifierRecord> allFound = new LinkedList<TechIdStringIdentifierRecord>(foundWithoutContainer); + + List<TechIdStringIdentifierRecord> foundWithSomeContainer = listWithSomeContainer.list(codesNotFound.toArray(new String[] {})); + Map<String, TechIdStringIdentifierRecord> foundWithSomeContainerMap = new HashMap<String, TechIdStringIdentifierRecord>(); + Map<String, Integer> foundWithSomeContainerCounter = new HashMap<String, Integer>(); + + for (TechIdStringIdentifierRecord found : foundWithSomeContainer) + { + foundWithSomeContainerMap.put(found.identifier, found); + + Integer counter = foundWithSomeContainerCounter.get(found.identifier); + counter = counter == null ? 1 : counter + 1; + foundWithSomeContainerCounter.put(found.identifier, counter); + } + + for (Map.Entry<String, Integer> counterEntry : foundWithSomeContainerCounter.entrySet()) + { + if (counterEntry.getValue() == 1) + { + TechIdStringIdentifierRecord found = foundWithSomeContainerMap.get(counterEntry.getKey()); + allFound.add(found); + } + } + + return allFound; + + } catch (Exception e) + { + throw CheckedExceptionTunnel.wrapIfNecessary(e); + } + } + + private static interface IListAction + { + public List<TechIdStringIdentifierRecord> list(String[] codesToList); + } + } diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SampleQuery.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SampleQuery.java index 7e3fd51e36234b25f2dd4a93ee99d31ceeec0c3b..83c2e191ad79b8b0099fb5930e43e142f71a5f8b 100644 --- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SampleQuery.java +++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SampleQuery.java @@ -26,8 +26,6 @@ import ch.ethz.sis.openbis.generic.server.asapi.v3.translator.entity.common.Obje import ch.systemsx.cisd.common.db.mapper.StringArrayMapper; /** - * - * * @author Franz-Josef Elmer */ public interface SampleQuery extends ObjectQuery @@ -39,38 +37,55 @@ public interface SampleQuery extends ObjectQuery @Select(sql = "select id, code as identifier from samples " + "where space_id is null and samp_id_part_of is null and code = any(?{1})", parameterBindings = { StringArrayMapper.class }, fetchSize = FETCH_SIZE) - public List<TechIdStringIdentifierRecord> listSharedSampleTechIdsByCodes(String[] codes); - + public List<TechIdStringIdentifierRecord> listSharedSampleTechIdsByCodesWithoutContainer(String[] codes); + + @Select(sql = "select id, code as identifier from samples " + + "where space_id is null and samp_id_part_of is not null and code = any(?{1})", parameterBindings = + { StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSharedSampleTechIdsByCodesWithSomeContainer(String[] codes); + @Select(sql = "select s.id, s.code as identifier from samples s join samples cs on s.samp_id_part_of = cs.id " + "where s.space_id is null and cs.code = ?{1} and s.code = any(?{2})", parameterBindings = - { TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) - public List<TechIdStringIdentifierRecord> listSharedSampleTechIdsByContainerCodeAndCodes(String containerCode, + { TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSharedSampleTechIdsByContainerCodeAndCodes(String containerCode, String[] codes); - + + @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id " + + "where sp.code = ?{1} and s.proj_id is null and samp_id_part_of is null and s.code = any(?{2})", + parameterBindings = { TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByCodesWithoutContainer(String spaceCode, String[] codes); + @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id " - + "where sp.code = ?{1} and s.proj_id is null and samp_id_part_of is null and s.code = any(?{2})", + + "where sp.code = ?{1} and s.proj_id is null and samp_id_part_of is not null and s.code = any(?{2})", parameterBindings = { TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) - public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByCodes(String spaceCode, String[] codes); - + public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByCodesWithSomeContainer(String spaceCode, String[] codes); + @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id " + "join samples cs on s.samp_id_part_of = cs.id " + "where sp.code = ?{1} and s.proj_id is null and cs.code = ?{2} and s.code = any(?{3})", parameterBindings = - { TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) - public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByContainerCodeAndCodes(String spaceCode, + { TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listSpaceSampleTechIdsByContainerCodeAndCodes(String spaceCode, String containerCode, String[] codes); - + @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id " + "join projects p on s.proj_id = p.id " + "where sp.code = ?{1} and samp_id_part_of is null and p.code = ?{2} and s.code = any(?{3})", parameterBindings = - { TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) - public List<TechIdStringIdentifierRecord> listProjectSampleTechIdsByCodes(String spaceCode, + { TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listProjectSampleTechIdsByCodesWithoutContainer(String spaceCode, + String projectCode, String[] codes); + + @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id " + + "join projects p on s.proj_id = p.id " + + "where sp.code = ?{1} and samp_id_part_of is not null and p.code = ?{2} and s.code = any(?{3})", parameterBindings = + { TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listProjectSampleTechIdsByCodesWithSomeContainer(String spaceCode, String projectCode, String[] codes); - + @Select(sql = "select s.id, s.code as identifier from samples s join spaces sp on s.space_id = sp.id " + "join projects p on s.proj_id = p.id " + "join samples cs on s.samp_id_part_of = cs.id " + "where sp.code = ?{1} and p.code = ?{2} and cs.code = ?{3} and s.code = any(?{4})", parameterBindings = - { TypeMapper.class, TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) - public List<TechIdStringIdentifierRecord> listProjectSampleTechIdsByContainerCodeAndCodes(String spaceCode, + { TypeMapper.class, TypeMapper.class, TypeMapper.class, StringArrayMapper.class }, fetchSize = FETCH_SIZE) + public List<TechIdStringIdentifierRecord> listProjectSampleTechIdsByContainerCodeAndCodes(String spaceCode, String projectCode, String containerCode, String[] codes); } diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/MapSampleTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/MapSampleTest.java index 82c58df92d4d8b3dd60fe04cc670976d40913d53..f755b10ec50db22a147fc22b439c3dc8a6186235 100644 --- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/MapSampleTest.java +++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/MapSampleTest.java @@ -129,6 +129,60 @@ public class MapSampleTest extends AbstractSampleTest v3api.logout(sessionToken); } + @Test + public void testMapByComponentIdentifierWithOmittedContainerCodeAndUniqueComponentCode() + { + String sessionToken = v3api.login(TEST_USER, PASSWORD); + + SampleIdentifier identifier1 = new SampleIdentifier("/CISD/WELL-A01"); + SampleIdentifier identifier2 = new SampleIdentifier("/CISD/WELL-A02"); + + Map<ISampleId, Sample> map = v3api.mapSamples(sessionToken, Arrays.asList(identifier1, identifier2), new SampleFetchOptions()); + + assertEquals(map.size(), 2); + + Sample sample1 = map.get(identifier1); + Sample sample2 = map.get(identifier2); + + assertEquals(sample1.getIdentifier().getIdentifier(), "/CISD/PLATE_WELLSEARCH:WELL-A01"); + assertEquals(sample2.getIdentifier().getIdentifier(), "/CISD/PLATE_WELLSEARCH:WELL-A02"); + + v3api.logout(sessionToken); + } + + @Test + public void testMapByComponentIdentifierWithOmittedContainerCodeAndNotUniqueComponentCode() + { + String sessionToken = v3api.login(TEST_USER, PASSWORD); + + SampleIdentifier identifier1 = new SampleIdentifier("/CISD/A01"); + SampleIdentifier identifier2 = new SampleIdentifier("/CISD/A02"); + + Map<ISampleId, Sample> map = v3api.mapSamples(sessionToken, Arrays.asList(identifier1, identifier2), new SampleFetchOptions()); + + assertEquals(map.size(), 0); + + v3api.logout(sessionToken); + } + + @Test + public void testMapByComponentIdentifierWithOmittedContainerCodeAndUniqueAndNotUniqueComponentCodes() + { + String sessionToken = v3api.login(TEST_USER, PASSWORD); + + SampleIdentifier identifier1 = new SampleIdentifier("/CISD/WELL-A01"); + SampleIdentifier identifier2 = new SampleIdentifier("/CISD/A02"); + + Map<ISampleId, Sample> map = v3api.mapSamples(sessionToken, Arrays.asList(identifier1, identifier2), new SampleFetchOptions()); + + assertEquals(map.size(), 1); + + Sample sample1 = map.get(identifier1); + assertEquals(sample1.getIdentifier().getIdentifier(), "/CISD/PLATE_WELLSEARCH:WELL-A01"); + + v3api.logout(sessionToken); + } + private SampleIdentifier normalize(SampleIdentifier identifier) { ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier identifier2 =