diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java index a688984356108c3b69c448cb7a1e3e572dd5a73d..f15e6a73c5e77b368d22c0056838e123f10d0c88 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetLister.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; @@ -38,6 +39,8 @@ import net.lemnik.eodsql.DataIterator; import org.apache.commons.lang.time.DateUtils; import ch.rinn.restrictions.Friend; +import ch.systemsx.cisd.common.collections.IKeyExtractor; +import ch.systemsx.cisd.common.collections.TableMap; import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.common.types.BooleanOrUnknown; import ch.systemsx.cisd.openbis.generic.server.business.bo.common.CodeRecord; @@ -207,6 +210,105 @@ public class DatasetLister extends AbstractLister implements IDatasetLister return map; } + public Map<Long, Set<Long>> listChildrenIds(Collection<Long> dataSetIDs) + { + LongOpenHashSet ids = new LongOpenHashSet(); + for (Long id : dataSetIDs) + { + ids.add(id); + } + DataIterator<DatasetRelationRecord> relationships = query.listChildrenDataSetIds(ids); + Map<Long, Set<Long>> map = new LinkedHashMap<Long, Set<Long>>(); + for (DatasetRelationRecord relationship : relationships) + { + Set<Long> children = map.get(relationship.data_id_parent); + if (children == null) + { + children = new LinkedHashSet<Long>(); + map.put(relationship.data_id_parent, children); + } + children.add(relationship.data_id_child); + } + return map; + } + + public Map<Sample, List<ExternalData>> listAllDataSetsFor(List<Sample> samples) + { + TableMap<Long, Sample> samplesByID = + new TableMap<Long, Sample>(samples, new IKeyExtractor<Long, Sample>() + { + public Long getKey(Sample e) + { + return e.getId(); + } + }); + Map<Sample, List<ExternalData>> result = new HashMap<Sample, List<ExternalData>>(); + Set<Long> sampleIDs = new HashSet<Long>(); + for (Sample sample : samples) + { + result.put(sample, new ArrayList<ExternalData>()); + sampleIDs.add(sample.getId()); + } + List<ExternalData> rootDataSets = listBySampleIds(sampleIDs); + addChildren(rootDataSets); + for (ExternalData dataSet : rootDataSets) + { + Sample sample = samplesByID.tryGet(dataSet.getSample().getId()); + assert sample != null; + result.get(sample).add(dataSet); + } + return result; + } + + private void addChildren(List<ExternalData> dataSets) + { + Map<Long, ExternalData> dataSetsByID = new HashMap<Long, ExternalData>(); + for (ExternalData dataSet : dataSets) + { + dataSetsByID.put(dataSet.getId(), dataSet); + } + Map<Long, Set<Long>> childrenIDs = listChildrenIds(dataSetsByID.keySet()); + Set<Entry<Long, Set<Long>>> entrySet = childrenIDs.entrySet(); + Map<Long, Set<Long>> child2ParentsMap = new HashMap<Long, Set<Long>>(); + Set<Long> childIDs = new HashSet<Long>(); + for (Entry<Long, Set<Long>> entry : entrySet) + { + Set<Long> value = entry.getValue(); + Long parentID = entry.getKey(); + for (Long childId : value) + { + childIDs.add(childId); + Set<Long> parents = child2ParentsMap.get(childId); + if (parents == null) + { + parents = new HashSet<Long>(1); + child2ParentsMap.put(childId, parents); + } + parents.add(parentID); + } + } + if (childIDs.isEmpty() == false) + { + List<ExternalData> children = listByDatasetIds(childIDs); + for (ExternalData child : children) + { + Set<Long> parentIDs = child2ParentsMap.get(child.getId()); + for (Long parentID : parentIDs) + { + ExternalData dataSet = dataSetsByID.get(parentID); + List<ExternalData> childList = dataSet.getChildren(); + if (childList == null) + { + childList = new ArrayList<ExternalData>(1); + dataSet.setChildren(childList); + } + childList.add(child); + } + } + addChildren(children); + } + } + public List<ExternalData> listByChildTechId(TechId childDatasetId) { return enrichDatasets(query.getParentDatasetsForChild(childDatasetId.getId())); diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetLister.java index 02de40f08c6ca7dc66ccb53e43a46047fd22d47f..08583f96e0795169af042369465752e45dfc6e2b 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetLister.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetLister.java @@ -24,6 +24,7 @@ import java.util.Set; import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ArchiverDataSetCriteria; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TrackingDataSetCriteria; /** @@ -51,10 +52,22 @@ public interface IDatasetLister /** * Returns a map with all parent data set IDs of specified data set IDs. The keys of the map are - * IDs from the argument. A value of the map contains at least one alement. + * IDs from the argument. A value of the map contains at least one element. */ Map<Long, Set<Long>> listParentIds(Collection<Long> dataSetIDs); + /** + * Returns a map with all child data set IDs of specified data set IDs. The keys of the map are + * IDs from the argument. A value of the map contains at least one element. + */ + Map<Long, Set<Long>> listChildrenIds(Collection<Long> dataSetIDs); + + /** + * Returns a map with all data sets of specified samples. The sample arguments are the + * key into the returned map. The returned data sets contains all derived data sets (children, + * grand children, etc.). + */ + Map<Sample, List<ExternalData>> listAllDataSetsFor(List<Sample> samples); // /** @return datasets with given ids */ diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetListingQuery.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetListingQuery.java index e2263f2d02321ce6d519855891a1f2e496ff0325..aa67e7e955562bfd1a28ac626209c98050ad1923 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetListingQuery.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/IDatasetListingQuery.java @@ -109,6 +109,10 @@ public interface IDatasetListingQuery extends TransactionQuery, IPropertyListing { LongSetMapper.class }, fetchSize = FETCH_SIZE) public DataIterator<DatasetRelationRecord> listParentDataSetIds(LongSet ids); + @Select(sql = "select * from data_set_relationships where data_id_parent = any(?{1})", parameterBindings = + { LongSetMapper.class }, fetchSize = FETCH_SIZE) + public DataIterator<DatasetRelationRecord> listChildrenDataSetIds(LongSet ids); + /** * Returns all datasets that are children of any specified dataset id. */ diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java index ac68f2bb0d5141e24428aea9c31f6d67b49d9025..13d9ad302f11bfb706e31c4732ec9873fd3391de 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/IExperimentDAO.java @@ -16,6 +16,7 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -40,6 +41,12 @@ public interface IExperimentDAO extends IGenericDAO<ExperimentPE> public List<ExperimentPE> listExperimentsWithProperties(final ProjectPE projectOrNull) throws DataAccessException; + /** + * Lists experiments with specified ids. Fetches also properties. + */ + public List<ExperimentPE> listExperimentsWithProperties(final Collection<Long> experimentIDs) + throws DataAccessException; + /** * Lists experiments of specified type and specified project. Fetches also properties. * diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java index afd7c9280500b519e48cb3967903a6ca949846dd..936cdd3682c68c2e5ca58523ced50debf2854bf7 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExperimentDAO.java @@ -17,6 +17,7 @@ package ch.systemsx.cisd.openbis.generic.server.dataaccess.db; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Set; @@ -89,6 +90,22 @@ public class ExperimentDAO extends AbstractGenericEntityWithPropertiesDAO<Experi return list; } + public List<ExperimentPE> listExperimentsWithProperties(Collection<Long> experimentIDs) + throws DataAccessException + { + DetachedCriteria criteria = DetachedCriteria.forClass(getEntityClass()); + criteria.add(Restrictions.in("id", experimentIDs)); + criteria.setFetchMode("experimentProperties", FetchMode.JOIN); + criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); + final List<ExperimentPE> list = cast(getHibernateTemplate().findByCriteria(criteria)); + if (operationLog.isDebugEnabled()) + { + operationLog.debug(String.format("%d experiments have been found for specified IDs.", + list.size())); + } + return list; + } + public List<ExperimentPE> listExperiments() throws DataAccessException { final List<ExperimentPE> list = cast(getHibernateTemplate().loadAll(getEntityClass())); diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java index e1272f4b4229132b1014ad0d90e5a9d2a7a9b44b..2ef33ef958ea8633a1d74662a925dab81eca3dd1 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java @@ -18,11 +18,14 @@ package ch.systemsx.cisd.openbis.generic.server.business.bo.datasetlister; import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertFalse; +import static org.testng.AssertJUnit.assertSame; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -37,7 +40,9 @@ import ch.systemsx.cisd.openbis.generic.server.business.bo.common.entity.Seconda import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.AbstractDAOTest; import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; +import ch.systemsx.cisd.openbis.generic.shared.translator.SampleTranslator; /** * @author Tomasz Pylak @@ -90,4 +95,83 @@ public class DatasetListerTest extends AbstractDAOTest assertEquals("[2, 5, 6, 7]", list.toString()); } + @Test + public void testListAllDataSetsFor() + { + HashSet<String> samplePermIDs = + new HashSet<String>(Arrays.asList("200811050946559-983", "200902091219327-1025")); + List<SamplePE> samplePEs = daoFactory.getSampleDAO().listByPermID(samplePermIDs); + List<Sample> samples = SampleTranslator.translate(samplePEs, ""); + + Map<Sample, List<ExternalData>> dataSets = lister.listAllDataSetsFor(samples); + + StringBuilder builder = new StringBuilder(); + for (Sample sample : samples) + { + builder.append(sample.getCode()); + appendChildren(builder, dataSets.get(sample), " "); + builder.append('\n'); + } + assertEquals("3VCP1\n 20081105092158673-1 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092159188-3 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092259000-9 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092259900-0 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092359990-2 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092259900-1 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092359990-2 (HCS_IMAGE) [COMMENT: no comment]\n" + + "CP-TEST-1\n" + + " 20081105092159111-1 (HCS_IMAGE) [ANY_MATERIAL: 1000_C (SIRNA), " + + "BACTERIUM: BACTERIUM1 (BACTERIUM), COMMENT: no comment, GENDER: FEMALE]\n" + + " 20081105092259000-9 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092259900-0 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092359990-2 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092259900-1 (HCS_IMAGE) [COMMENT: no comment]\n" + + " 20081105092359990-2 (HCS_IMAGE) [COMMENT: no comment]\n", + builder.toString()); + Map<String, ExternalData> dataSetsByCode = new HashMap<String, ExternalData>(); + for (Sample sample : samples) + { + List<ExternalData> rootDataSets = dataSets.get(sample); + assertSameDataSetsForSameCode(dataSetsByCode, rootDataSets); + } + } + + private void assertSameDataSetsForSameCode(Map<String, ExternalData> dataSetsByCode, + List<ExternalData> dataSets) + { + if (dataSets == null || dataSets.isEmpty()) + { + return; + } + for (ExternalData dataSet : dataSets) + { + ExternalData previousDataSet = dataSetsByCode.put(dataSet.getCode(), dataSet); + if (previousDataSet != null) + { + assertSame("Same data set object expected for " + dataSet.getCode(), previousDataSet, + dataSet); + } + List<ExternalData> children = dataSet.getChildren(); + assertSameDataSetsForSameCode(dataSetsByCode, children); + } + } + + private void appendChildren(StringBuilder builder, List<ExternalData> dataSets, + String indentation) + { + if (dataSets.isEmpty() == false) + { + for (ExternalData dataSet : dataSets) + { + builder.append('\n').append(indentation).append(dataSet.getCode()).append(" ("); + builder.append(dataSet.getDataSetType().getCode()).append(") "); + builder.append(getSortedProperties(dataSet)); + List<ExternalData> children = dataSet.getChildren(); + if (children != null && children.isEmpty() == false) + { + appendChildren(builder, children, indentation + " "); + } + } + } + } } diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AbstractDAOWithoutContextTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AbstractDAOWithoutContextTest.java index c1837492d1ef25fb0e1121f6b24950ae3d1dec60..29e981a8782283b7d180ba26156cfaccb6d9e25f 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AbstractDAOWithoutContextTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/AbstractDAOWithoutContextTest.java @@ -22,6 +22,7 @@ import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.fail; import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.List; @@ -41,6 +42,8 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.IExternalDataDAO; import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.HibernateSearchContext; import ch.systemsx.cisd.openbis.generic.server.util.TestInitializer; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataTypeCode; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityPropertiesHolder; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty; import ch.systemsx.cisd.openbis.generic.shared.dto.AuthorizationGroupPE; import ch.systemsx.cisd.openbis.generic.shared.dto.Code; import ch.systemsx.cisd.openbis.generic.shared.dto.DataTypePE; @@ -362,4 +365,17 @@ public abstract class AbstractDAOWithoutContextTest extends result.setRegistrator(getSystemPerson()); return result; } + + protected List<IEntityProperty> getSortedProperties(IEntityPropertiesHolder sample) + { + List<IEntityProperty> properties = sample.getProperties(); + Collections.sort(properties, new Comparator<IEntityProperty>() + { + public int compare(IEntityProperty p1, IEntityProperty p2) + { + return p1.getPropertyType().getCode().compareTo(p2.getPropertyType().getCode()); + } + }); + return properties; + } } diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java index 7b13d6e5a6d6ff6202c75b2c20cb2f9a2b81174b..5eedb302435de1d880853d4efad1bda44785f532 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/util/TestInitializer.java @@ -32,11 +32,11 @@ public class TestInitializer LogInitializer.init(); System.setProperty("database.create-from-scratch", "true"); System.setProperty("database.kind", "test"); - System.setProperty("script-folder", "sourceTest"); + System.setProperty("script-folder", "../openbis/sourceTest"); System.setProperty("hibernate.search.index-mode", "NO_INDEX"); System.setProperty("hibernate.search.index-base", LUCENE_INDEX_PATH); System.setProperty("hibernate.search.worker.execution", "sync"); - System.setProperty("mass-upload-folder", "sourceTest/sql/postgresql"); + System.setProperty("mass-upload-folder", "../openbis/sourceTest/sql/postgresql"); } }