diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java index bcc608330bbebe39e73caaa34b581a20bcf5662d..5f750f4ca1fcd476b279bf813027aa3555439f7d 100644 --- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java +++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java @@ -118,6 +118,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleAssignment; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy.RoleCode; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space; @@ -126,7 +127,6 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.UpdatedSample; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Vocabulary; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTerm; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.VocabularyTermReplacement; -import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy.RoleCode; import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentHolderPE; import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentPE; import ch.systemsx.cisd.openbis.generic.shared.dto.AuthorizationGroupPE; @@ -169,6 +169,7 @@ import ch.systemsx.cisd.openbis.generic.shared.translator.DataTypeTranslator; import ch.systemsx.cisd.openbis.generic.shared.translator.DtoConverters; import ch.systemsx.cisd.openbis.generic.shared.translator.ExperimentTranslator; import ch.systemsx.cisd.openbis.generic.shared.translator.ExternalDataTranslator; +import ch.systemsx.cisd.openbis.generic.shared.translator.GridCustomExpressionTranslator.GridCustomFilterTranslator; import ch.systemsx.cisd.openbis.generic.shared.translator.GroupTranslator; import ch.systemsx.cisd.openbis.generic.shared.translator.MaterialTypeTranslator; import ch.systemsx.cisd.openbis.generic.shared.translator.PersonTranslator; @@ -179,7 +180,6 @@ import ch.systemsx.cisd.openbis.generic.shared.translator.SampleTypeTranslator; import ch.systemsx.cisd.openbis.generic.shared.translator.TypeTranslator; import ch.systemsx.cisd.openbis.generic.shared.translator.VocabularyTermTranslator; import ch.systemsx.cisd.openbis.generic.shared.translator.VocabularyTranslator; -import ch.systemsx.cisd.openbis.generic.shared.translator.GridCustomExpressionTranslator.GridCustomFilterTranslator; import ch.systemsx.cisd.openbis.generic.shared.util.EntityHelper; import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils; @@ -402,8 +402,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl { IHibernateSearchDAO searchDAO = getDAOFactory().getHibernateSearchDAO(); final Collection<Long> sampleIds = - searchDAO.searchForEntityIds(criteria, DtoConverters - .convertEntityKind(EntityKind.SAMPLE)); + searchDAO.searchForEntityIds(criteria, + DtoConverters.convertEntityKind(EntityKind.SAMPLE)); final ISampleLister sampleLister = businessObjectFactory.createSampleLister(session); return sampleLister.list(new ListOrSearchSampleCriteria(sampleIds)); } catch (final DataAccessException ex) @@ -447,7 +447,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl datasets = datasetLister.listByChildTechId(datasetId); break; case PARENT: - datasets = datasetLister.listByParentTechId(datasetId); + datasets = datasetLister.listByParentTechIds(Arrays.asList(datasetId.getId())); break; } Collections.sort(datasets); @@ -617,8 +617,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl Session session = getSession(sessionToken); IEntityTypePropertyTypeBO etptBO = - businessObjectFactory.createEntityTypePropertyTypeBO(session, DtoConverters - .convertEntityKind(entityKind)); + businessObjectFactory.createEntityTypePropertyTypeBO(session, + DtoConverters.convertEntityKind(entityKind)); etptBO.loadAssignment(propertyTypeCode, entityTypeCode); etptBO.updateLoadedAssignment(isMandatory, defaultValue, section, previousETPTOrdinal); } @@ -630,8 +630,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl Session session = getSession(sessionToken); IEntityTypePropertyTypeBO etptBO = - businessObjectFactory.createEntityTypePropertyTypeBO(session, DtoConverters - .convertEntityKind(entityKind)); + businessObjectFactory.createEntityTypePropertyTypeBO(session, + DtoConverters.convertEntityKind(entityKind)); etptBO.loadAssignment(propertyTypeCode, entityTypeCode); etptBO.deleteLoadedAssignment(); } @@ -643,8 +643,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl Session session = getSession(sessionToken); IEntityTypePropertyTypeBO etptBO = - businessObjectFactory.createEntityTypePropertyTypeBO(session, DtoConverters - .convertEntityKind(entityKind)); + businessObjectFactory.createEntityTypePropertyTypeBO(session, + DtoConverters.convertEntityKind(entityKind)); return etptBO.countAssignmentValues(propertyTypeCode, entityTypeCode); } @@ -756,8 +756,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl IHibernateSearchDAO searchDAO = getDAOFactory().getHibernateSearchDAO(); final Collection<Long> datasetIds = - searchDAO.searchForEntityIds(criteria, DtoConverters - .convertEntityKind(EntityKind.DATA_SET)); + searchDAO.searchForEntityIds(criteria, + DtoConverters.convertEntityKind(EntityKind.DATA_SET)); final IDatasetLister datasetLister = createDatasetLister(session); return datasetLister.listByDatasetIds(datasetIds); } catch (final DataAccessException ex) @@ -903,8 +903,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl getDAOFactory().getFileFormatTypeDAO().createOrUpdate(fileFormatType); } catch (final DataAccessException ex) { - DataAccessExceptionTranslator.throwException(ex, String.format( - "File format type '%s' ", fileFormatType.getCode()), null); + DataAccessExceptionTranslator.throwException(ex, + String.format("File format type '%s' ", fileFormatType.getCode()), null); } } @@ -1172,8 +1172,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl { IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session); experimentBO.loadDataByTechId(experimentId); - return AttachmentTranslator.translate(listHolderAttachments(session, experimentBO - .getExperiment()), session.getBaseIndexURL()); + return AttachmentTranslator.translate( + listHolderAttachments(session, experimentBO.getExperiment()), + session.getBaseIndexURL()); } catch (final DataAccessException ex) { throw createUserFailureException(ex); @@ -1187,8 +1188,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl { ISampleBO sampleBO = businessObjectFactory.createSampleBO(session); sampleBO.loadDataByTechId(sampleId); - return AttachmentTranslator.translate(listHolderAttachments(session, sampleBO - .getSample()), session.getBaseIndexURL()); + return AttachmentTranslator + .translate(listHolderAttachments(session, sampleBO.getSample()), + session.getBaseIndexURL()); } catch (final DataAccessException ex) { throw createUserFailureException(ex); @@ -1202,8 +1204,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl { IProjectBO projectBO = businessObjectFactory.createProjectBO(session); projectBO.loadDataByTechId(projectId); - return AttachmentTranslator.translate(listHolderAttachments(session, projectBO - .getProject()), session.getBaseIndexURL()); + return AttachmentTranslator.translate( + listHolderAttachments(session, projectBO.getProject()), + session.getBaseIndexURL()); } catch (final DataAccessException ex) { throw createUserFailureException(ex); @@ -1346,8 +1349,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl { if (entityOrNull == null) { - throw UserFailureException.fromTemplate("There is no %s with permId '%s'.", kind - .getDescription(), permId); + throw UserFailureException.fromTemplate("There is no %s with permId '%s'.", + kind.getDescription(), permId); } return createInformationHolder(kind, entityOrNull); } @@ -1450,10 +1453,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl } catch (DataIntegrityViolationException ex) { throw new UserFailureException( - String - .format( - "File format type '%s' is being used. Use 'Data Set Search' to find all connected data sets.", - code)); + String.format( + "File format type '%s' is being used. Use 'Data Set Search' to find all connected data sets.", + code)); } } } @@ -1482,12 +1484,11 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl if (types.size() != 1) { section = - String - .format( - "[%s]\n%s%s\n", - entityType.getCode(), - firstSection ? "# Comments must be located after the type declaration ('[TYPE]').\n" - : "", section); + String.format( + "[%s]\n%s%s\n", + entityType.getCode(), + firstSection ? "# Comments must be located after the type declaration ('[TYPE]').\n" + : "", section); } sb.append(section); firstSection = false; @@ -1674,8 +1675,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServer> impl IExternalDataTable externalDataTable = businessObjectFactory.createExternalDataTable(session); Map<String, String> parameterBindings = new HashMap<String, String>(); - externalDataTable.processDatasets(serviceDescription.getKey(), serviceDescription - .getDatastoreCode(), datasetCodes, parameterBindings); + externalDataTable.processDatasets(serviceDescription.getKey(), + serviceDescription.getDatastoreCode(), datasetCodes, parameterBindings); } public void registerAuthorizationGroup(String sessionToken, 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 fef98587ae91649d944fff3cdd7fe0e941224a9f..437a7d4e4001009b543d3b81fa7fc24293df2797 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 @@ -30,8 +30,8 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.Map.Entry; +import java.util.Set; import net.lemnik.eodsql.DataIterator; @@ -210,9 +210,10 @@ public class DatasetLister implements IDatasetLister return enrichDatasets(query.getParentDatasetsForChild(childDatasetId.getId())); } - public List<ExternalData> listByParentTechId(TechId parentDatasetId) + public List<ExternalData> listByParentTechIds(Collection<Long> parentDatasetIds) { - return enrichDatasets(query.getChildDatasetsForParent(parentDatasetId.getId())); + return enrichDatasets(query + .getChildDatasetsForParents(new LongOpenHashSet(parentDatasetIds))); } public List<ExternalData> listByDatasetIds(Collection<Long> datasetIds) @@ -225,8 +226,8 @@ public class DatasetLister implements IDatasetLister Long sampleTypeId = referencedEntityDAO.getSampleTypeIdForSampleTypeCode(criteria .getConnectedSampleTypeCode()); - return enrichDatasets(query.getNewDataSetsForSampleType(sampleTypeId, criteria - .getLastSeenDataSetId())); + return enrichDatasets(query.getNewDataSetsForSampleType(sampleTypeId, + criteria.getLastSeenDataSetId())); } public List<ExternalData> listByArchiverCriteria(String dataStoreCode, 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 14a4b92c080db269f146d9c670019bcc12f6e01e..02de40f08c6ca7dc66ccb53e43a46047fd22d47f 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 @@ -46,8 +46,8 @@ public interface IDatasetLister /** @return datasets that are parents of a dataset with the specified id */ List<ExternalData> listByChildTechId(TechId childDatasetId); - /** @return datasets that are children of a dataset with the specified id */ - List<ExternalData> listByParentTechId(TechId parentDatasetId); + /** @return all datasets that are children of any specified dataset id */ + List<ExternalData> listByParentTechIds(Collection<Long> parentDatasetIds); /** * Returns a map with all parent data set IDs of specified data set IDs. The keys of the map are 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 8b1baed17367118c994bc441ba358a16d69f6118..e2263f2d02321ce6d519855891a1f2e496ff0325 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 @@ -110,11 +110,12 @@ public interface IDatasetListingQuery extends TransactionQuery, IPropertyListing public DataIterator<DatasetRelationRecord> listParentDataSetIds(LongSet ids); /** - * Returns the datasets that are children of a dataset with given id. + * Returns all datasets that are children of any specified dataset id. */ @Select(sql = "SELECT * FROM data JOIN external_data ON data.id = external_data.data_id" - + " WHERE data.id IN (SELECT data_id_child FROM data_set_relationships r WHERE r.data_id_parent=?{1})", fetchSize = FETCH_SIZE) - public DataIterator<DatasetRecord> getChildDatasetsForParent(long parentDatasetId); + + " WHERE data.id IN (SELECT data_id_child FROM data_set_relationships r WHERE r.data_id_parent = any(?{1}))", parameterBindings = + { LongSetMapper.class }, fetchSize = FETCH_SIZE) + public DataIterator<DatasetRecord> getChildDatasetsForParents(LongSet parentDatasetIds); /** * Returns the datasets that are parents of a dataset with given id. diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListingQueryTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListingQueryTest.java index 4d18229b6dd1b8458ca4e4c2e2a47c89604ba185..d296588591a828c802b29adecf5d7d568d2f9d1c 100644 --- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListingQueryTest.java +++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListingQueryTest.java @@ -22,6 +22,8 @@ import static org.testng.AssertJUnit.assertEquals; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertTrue; import it.unimi.dsi.fastutil.longs.LongArraySet; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import it.unimi.dsi.fastutil.longs.LongSet; import java.sql.SQLException; import java.util.Arrays; @@ -132,7 +134,7 @@ public class DatasetListingQueryTest extends AbstractDAOTest ExperimentPE experiment1 = getExperiment(dbInstance.getCode(), "CISD", "NEMO", "EXP-TEST-1", daoFactory); ExperimentPE experiment2 = - getExperiment(dbInstance.getCode(), "CISD", "NEMO", "EXP-TEST-2", daoFactory); + getExperiment(dbInstance.getCode(), "CISD", "NEMO", "EXP-TEST-2", daoFactory); experimentIds.add((long) experiment1.getId()); experimentIds.add((long) experiment2.getId()); List<DatasetRecord> datasets = asList(query.getDatasetsForExperiment(experimentIds)); @@ -144,7 +146,7 @@ public class DatasetListingQueryTest extends AbstractDAOTest assertEqualWithFetchedById(record); counters.count(record.expe_id); } - + assertEquals(1, counters.getCountOf(experiment1.getId())); assertEquals(1, counters.getCountOf(experiment2.getId())); assertEquals(2, counters.getNumberOfDifferentObjectsCounted()); @@ -210,8 +212,9 @@ public class DatasetListingQueryTest extends AbstractDAOTest @Test public void testChildDatasetsForParent() { - long datasetId = 2; - List<DatasetRecord> children = asList(query.getChildDatasetsForParent(datasetId)); + LongSet datasetIds = new LongOpenHashSet(new long[] + { 2 }); + List<DatasetRecord> children = asList(query.getChildDatasetsForParents(datasetIds)); assertEquals(2, children.size()); } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableBuilder.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableBuilder.java index 469d37836cc7b16649188c9d82bc5242ea8fbf85..6b438b328347c02f149bf0dc24af817ea779664c 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableBuilder.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableBuilder.java @@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.dss.generic.server; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -28,6 +29,9 @@ import java.util.Map.Entry; import java.util.Set; import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.openbis.dss.generic.server.featurevectors.FeatureTableRow; +import ch.systemsx.cisd.openbis.dss.generic.server.featurevectors.FeatureVectorValues; +import ch.systemsx.cisd.openbis.dss.generic.server.featurevectors.WellFeatureVectorReference; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.CodeAndLabel; import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier; @@ -70,7 +74,7 @@ public class FeatureTableBuilder private final boolean useAllFeatures; /** fetches all features of specified wells */ - public static WellFeatureCollection fetchWellFeatures( + public static WellFeatureCollection<FeatureTableRow> fetchWellFeatures( List<FeatureVectorDatasetWellReference> references, IImagingReadonlyQueryDAO dao, IEncapsulatedOpenBISService service) { @@ -82,18 +86,30 @@ public class FeatureTableBuilder * * @param featureCodes empty list means no filtering. */ - public static WellFeatureCollection fetchWellFeatures( + public static WellFeatureCollection<FeatureTableRow> fetchWellFeatures( List<FeatureVectorDatasetWellReference> references, List<String> featureCodes, IImagingReadonlyQueryDAO dao, IEncapsulatedOpenBISService service) { FeatureTableBuilder builder = new FeatureTableBuilder(featureCodes, dao, service); Set<String> datasetCodes = extractDatasetCodes(references); - for (String datasetCode : datasetCodes) - { - builder.addFeatureVectorsOfDataSet(datasetCode); - } + addFeatureVectorsOfDataSets(builder, datasetCodes); List<FeatureTableRow> features = builder.createFeatureTableRows(references); - return new WellFeatureCollection(features, builder.getCodesAndLabels()); + return new WellFeatureCollection<FeatureTableRow>(features, builder.getCodesAndLabels()); + } + + /** + * fetches all features of specified wells, used basic data types + */ + public static WellFeatureCollection<FeatureVectorValues> fetchWellFeatureValues( + List<WellFeatureVectorReference> references, IImagingReadonlyQueryDAO dao, + IEncapsulatedOpenBISService service) + { + FeatureTableBuilder builder = + new FeatureTableBuilder(new ArrayList<String>(), dao, service); + Set<String> datasetCodes = extractDatasetCodesFromSimpleReferences(references); + addFeatureVectorsOfDataSets(builder, datasetCodes); + List<FeatureVectorValues> features = builder.createFeatureVectorValues(references); + return new WellFeatureCollection<FeatureVectorValues>(features, builder.getCodesAndLabels()); } /** @@ -101,33 +117,30 @@ public class FeatureTableBuilder * * @param featureCodes empty list means no filtering. */ - public static WellFeatureCollection fetchDatasetFeatures(List<String> datasetCodes, - List<String> featureCodes, IImagingReadonlyQueryDAO dao, + public static WellFeatureCollection<FeatureTableRow> fetchDatasetFeatures( + List<String> datasetCodes, List<String> featureCodes, IImagingReadonlyQueryDAO dao, IEncapsulatedOpenBISService service) { FeatureTableBuilder builder = new FeatureTableBuilder(featureCodes, dao, service); - for (String datasetCode : datasetCodes) - { - builder.addFeatureVectorsOfDataSet(datasetCode); - } + addFeatureVectorsOfDataSets(builder, datasetCodes); List<FeatureTableRow> features = builder.createFeatureTableRows(); - return new WellFeatureCollection(features, builder.getCodesAndLabels()); + return new WellFeatureCollection<FeatureTableRow>(features, builder.getCodesAndLabels()); } /** stores feature vectors for a set of wells */ - public static class WellFeatureCollection + public static class WellFeatureCollection<T extends FeatureVectorValues> { - private final List<FeatureTableRow> features; + private final List<T> features; private final List<CodeAndLabel> featureNames; - public WellFeatureCollection(List<FeatureTableRow> features, List<CodeAndLabel> featureNames) + public WellFeatureCollection(List<T> features, List<CodeAndLabel> featureNames) { this.features = features; this.featureNames = featureNames; } - public List<FeatureTableRow> getFeatures() + public List<T> getFeatures() { return features; } @@ -159,6 +172,26 @@ public class FeatureTableBuilder } } + private static void addFeatureVectorsOfDataSets(FeatureTableBuilder builder, + Collection<String> datasetCodes) + { + for (String datasetCode : datasetCodes) + { + builder.addFeatureVectorsOfDataSet(datasetCode); + } + } + + private static Set<String> extractDatasetCodesFromSimpleReferences( + List<WellFeatureVectorReference> references) + { + Set<String> datasetCodes = new HashSet<String>(); + for (WellFeatureVectorReference ref : references) + { + datasetCodes.add(ref.getDatasetCode()); + } + return datasetCodes; + } + private static Set<String> extractDatasetCodes( List<FeatureVectorDatasetWellReference> references) { @@ -262,7 +295,6 @@ public class FeatureTableBuilder List<FeatureTableRow> rows = new ArrayList<FeatureTableRow>(); for (DatasetFeaturesBundle bundle : bundles) { - String dataSetCode = bundle.dataSet.getPermId(); ImgContainerDTO container = dao.getContainerById(bundle.dataSet.getContainerId()); SampleIdentifier identifier = service.tryToGetSampleIdentifier(container.getPermId()); for (int rowIndex = 1; rowIndex <= container.getNumberOfRows(); rowIndex++) @@ -270,8 +302,8 @@ public class FeatureTableBuilder for (int colIndex = 1; colIndex <= container.getNumberOfColumns(); colIndex++) { final FeatureTableRow row = - createFeatureTableRow(bundle.featureDefToValuesMap, dataSetCode, - identifier, null, new WellPosition(rowIndex, colIndex)); + createFeatureTableRow(bundle, identifier, null, new WellPosition( + rowIndex, colIndex)); rows.add(row); } } @@ -279,6 +311,26 @@ public class FeatureTableBuilder return rows; } + /** + * Returns all features for the specified wells in previously loaded datasets. Operates on very + * basic data types. + */ + private List<FeatureVectorValues> createFeatureVectorValues( + List<WellFeatureVectorReference> references) + { + Map<String/* dataset code */, DatasetFeaturesBundle> bundleMap = createBundleMap(bundles); + List<FeatureVectorValues> featureVectors = new ArrayList<FeatureVectorValues>(); + for (WellFeatureVectorReference reference : references) + { + String dataSetCode = reference.getDatasetCode(); + DatasetFeaturesBundle bundle = getDatasetFeaturesBundleOrDie(bundleMap, dataSetCode); + FeatureVectorValues featureVector = + createFeatureVector(bundle, reference.getWellPosition()); + featureVectors.add(featureVector); + } + return featureVectors; + } + /** * Returns all features for the specified wells in previously loaded datasets. */ @@ -290,21 +342,28 @@ public class FeatureTableBuilder for (FeatureVectorDatasetWellReference reference : references) { String dataSetCode = reference.getDatasetCode(); - DatasetFeaturesBundle bundle = bundleMap.get(dataSetCode); - if (bundle == null) - { - throw new IllegalStateException("Dataset has not been loaded: " + dataSetCode); - } + DatasetFeaturesBundle bundle = getDatasetFeaturesBundleOrDie(bundleMap, dataSetCode); ImgContainerDTO container = dao.getContainerById(bundle.dataSet.getContainerId()); SampleIdentifier identifier = service.tryToGetSampleIdentifier(container.getPermId()); final FeatureTableRow row = - createFeatureTableRow(bundle.featureDefToValuesMap, dataSetCode, identifier, - reference, reference.getWellPosition()); + createFeatureTableRow(bundle, identifier, reference, + reference.getWellPosition()); rows.add(row); } return rows; } + private DatasetFeaturesBundle getDatasetFeaturesBundleOrDie( + Map<String, DatasetFeaturesBundle> bundleMap, String dataSetCode) + { + DatasetFeaturesBundle bundle = bundleMap.get(dataSetCode); + if (bundle == null) + { + throw new IllegalStateException("Dataset has not been loaded: " + dataSetCode); + } + return bundle; + } + private static HashMap<String, DatasetFeaturesBundle> createBundleMap( List<DatasetFeaturesBundle> bundles) { @@ -316,16 +375,32 @@ public class FeatureTableBuilder return map; } - private FeatureTableRow createFeatureTableRow( - Map<ImgFeatureDefDTO, List<ImgFeatureValuesDTO>> featureDefToValuesMap, - String dataSetCode, SampleIdentifier identifier, - FeatureVectorDatasetWellReference reference, WellPosition wellPosition) + private FeatureTableRow createFeatureTableRow(DatasetFeaturesBundle bundle, + SampleIdentifier identifier, FeatureVectorDatasetWellReference reference, + WellPosition wellPosition) { - FeatureTableRow row = new FeatureTableRow(); - row.setDataSetCode(dataSetCode); + FeatureVectorValues featureVector = createFeatureVector(bundle, wellPosition); + FeatureTableRow row = new FeatureTableRow(featureVector); row.setPlateIdentifier(identifier); row.setReference(reference); - row.setWellPosition(wellPosition); + return row; + } + + private FeatureVectorValues createFeatureVector(DatasetFeaturesBundle bundle, + WellPosition wellPosition) + { + FeatureVectorValues fv = new FeatureVectorValues(); + fv.setDataSetCode(bundle.dataSet.getPermId()); + fv.setWellPosition(wellPosition); + float[] valueArray = createFeatureValueArray(bundle.featureDefToValuesMap, wellPosition); + fv.setFeatureValues(valueArray); + return fv; + } + + private float[] createFeatureValueArray( + Map<ImgFeatureDefDTO, List<ImgFeatureValuesDTO>> featureDefToValuesMap, + WellPosition wellPosition) + { float[] valueArray = new float[featureCodeLabelToIndexMap.size()]; Arrays.fill(valueArray, Float.NaN); for (Entry<ImgFeatureDefDTO, List<ImgFeatureValuesDTO>> entry : featureDefToValuesMap @@ -348,8 +423,7 @@ public class FeatureTableBuilder featureValues.getForWellLocation(wellPosition.getWellRow(), wellPosition.getWellColumn()); } - row.setFeatureValues(valueArray); - return row; + return valueArray; } private CodeAndLabel getCodeAndLabel(final ImgFeatureDefDTO featureDefinition) diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphServlet.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphServlet.java index 2cb872ff7e233cd4d192a27b0af6a54e05205fb1..c8870edea08fa37d304c427d660f269705880986 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphServlet.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/TabularDataGraphServlet.java @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.List; import ch.systemsx.cisd.openbis.dss.generic.server.FeatureTableBuilder.WellFeatureCollection; +import ch.systemsx.cisd.openbis.dss.generic.server.featurevectors.FeatureTableRow; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.ITabularData; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider; @@ -85,7 +86,7 @@ public class TabularDataGraphServlet extends AbstractTabularDataGraphServlet private void initialize() { - WellFeatureCollection featureCollection = + WellFeatureCollection<FeatureTableRow> featureCollection = FeatureTableBuilder.fetchDatasetFeatures(Arrays.asList(dataSetCode), new ArrayList<String>(), dao, service); diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableRow.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/FeatureTableRow.java similarity index 53% rename from screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableRow.java rename to screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/FeatureTableRow.java index 010240425d8da34539f2427fdc8d1a7075eb3324..aed3481b0be4e5cd3fc49e42e9021a1fe15877bb 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableRow.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/FeatureTableRow.java @@ -14,39 +14,28 @@ * limitations under the License. */ -package ch.systemsx.cisd.openbis.dss.generic.server; +package ch.systemsx.cisd.openbis.dss.generic.server.featurevectors; import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetWellReference; -import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition; /** * Bean for a row in a table of feature vectors. Each row is specified by data set code, plate - * identifier, well position and and array of feature values. Double.NaN is used for unknown - * feature value in this array. + * identifier, well position and and array of feature values. * * @author Franz-Josef Elmer */ -public class FeatureTableRow +public class FeatureTableRow extends FeatureVectorValues { - private String dataSetCode; - private FeatureVectorDatasetWellReference reference; private SampleIdentifier plateIdentifier; - private WellPosition wellPosition; - - private float[] featureValues; - - public final String getDataSetCode() + public FeatureTableRow(FeatureVectorValues featureVector) { - return dataSetCode; - } - - public final void setDataSetCode(String dataSetCode) - { - this.dataSetCode = dataSetCode; + setDataSetCode(featureVector.getDataSetCode()); + setFeatureValues(featureVector.getFeatureValues()); + setWellPosition(featureVector.getWellPosition()); } public FeatureVectorDatasetWellReference getReference() @@ -68,34 +57,4 @@ public class FeatureTableRow { this.plateIdentifier = plateIdentifier; } - - public void setWellPosition(WellPosition wellPosition) - { - this.wellPosition = wellPosition; - } - - public final WellPosition getWellPosition() - { - return wellPosition; - } - - public final float[] getFeatureValues() - { - return featureValues; - } - - public final double[] getFeatureValuesAsDouble() - { - final double[] doubleValues = new double[featureValues.length]; - for (int i = 0; i < featureValues.length; ++i) - { - doubleValues[i] = featureValues[i]; - } - return doubleValues; - } - - public final void setFeatureValues(float[] featureValues) - { - this.featureValues = featureValues; - } } diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/FeatureVectorValues.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/FeatureVectorValues.java new file mode 100644 index 0000000000000000000000000000000000000000..d454894c077766d057dcb99bbb8bc00950aa988b --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/FeatureVectorValues.java @@ -0,0 +1,73 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.featurevectors; + +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition; + +/** + * Bean for one feature vector of the well. Contains data set code, well position and and array of + * feature values. Double.NaN is used for unknown feature value in this array. + * + * @author Tomasz Pylak + */ +public class FeatureVectorValues +{ + private WellFeatureVectorReference featureVectorReference = new WellFeatureVectorReference(); + + private float[] featureValues; + + public float[] getFeatureValues() + { + return featureValues; + } + + public double[] getFeatureValuesAsDouble() + { + double[] doubleValues = new double[featureValues.length]; + for (int i = 0; i < featureValues.length; ++i) + { + doubleValues[i] = featureValues[i]; + } + return doubleValues; + } + + public void setFeatureValues(float[] featureValues) + { + this.featureValues = featureValues; + } + + public String getDataSetCode() + { + return featureVectorReference.getDatasetCode(); + } + + public void setDataSetCode(String dataSetCode) + { + featureVectorReference.setDatasetCode(dataSetCode); + } + + public void setWellPosition(WellPosition wellPosition) + { + featureVectorReference.setWellPosition(wellPosition); + } + + public WellPosition getWellPosition() + { + return featureVectorReference.getWellPosition(); + } + +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/WellFeatureVectorReference.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/WellFeatureVectorReference.java new file mode 100644 index 0000000000000000000000000000000000000000..0922c9eb36ca7d080e392c50f11861255924ee1e --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/featurevectors/WellFeatureVectorReference.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010 ETH Zuerich, CISD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ch.systemsx.cisd.openbis.dss.generic.server.featurevectors; + +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.WellPosition; + +/** + * References a feature vector of one well + * + * @author Tomasz Pylak + */ +public class WellFeatureVectorReference +{ + private String dataSetCode; // dataset with feature vectors + + private WellPosition wellPosition; + + public final String getDatasetCode() + { + return dataSetCode; + } + + public final void setDatasetCode(String dataSetCode) + { + this.dataSetCode = dataSetCode; + } + + public void setWellPosition(WellPosition wellPosition) + { + this.wellPosition = wellPosition; + } + + public final WellPosition getWellPosition() + { + return wellPosition; + } +} diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/ImageAnalysisMergedRowsReportingPlugin.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/ImageAnalysisMergedRowsReportingPlugin.java index 93e70cbc3ca6f0e1ed10465ef92b9700136b6750..fa937cfa5099d03032e32b1f392fe148cf9722fd 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/ImageAnalysisMergedRowsReportingPlugin.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/generic/server/plugins/ImageAnalysisMergedRowsReportingPlugin.java @@ -23,7 +23,7 @@ import java.util.Properties; import ch.systemsx.cisd.openbis.dss.generic.server.FeatureTableBuilder; import ch.systemsx.cisd.openbis.dss.generic.server.FeatureTableBuilder.WellFeatureCollection; -import ch.systemsx.cisd.openbis.dss.generic.server.FeatureTableRow; +import ch.systemsx.cisd.openbis.dss.generic.server.featurevectors.FeatureTableRow; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.standard.AbstractDatastorePlugin; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.IReportingPluginTask; import ch.systemsx.cisd.openbis.dss.generic.server.plugins.tasks.SimpleTableModelBuilder; @@ -82,7 +82,7 @@ public class ImageAnalysisMergedRowsReportingPlugin extends AbstractDatastorePlu { List<String> datasetCodes = extractDatasetCodes(datasets); ArrayList<String> featureCodes = new ArrayList<String>(); // fetch all - WellFeatureCollection featuresCollection = + WellFeatureCollection<FeatureTableRow> featuresCollection = FeatureTableBuilder.fetchDatasetFeatures(datasetCodes, featureCodes, getDAO(), getService()); diff --git a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java index f0b29b0f271e046633ba7e96746ac2fec4629311..0ee7ce3f30d9a306f27d60c5e6f98d441ed92763 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/dss/screening/server/DssServiceRpcScreening.java @@ -42,7 +42,7 @@ import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDatasetDownloadServle import ch.systemsx.cisd.openbis.dss.generic.server.AbstractDssServiceRpc; import ch.systemsx.cisd.openbis.dss.generic.server.FeatureTableBuilder; import ch.systemsx.cisd.openbis.dss.generic.server.FeatureTableBuilder.WellFeatureCollection; -import ch.systemsx.cisd.openbis.dss.generic.server.FeatureTableRow; +import ch.systemsx.cisd.openbis.dss.generic.server.featurevectors.FeatureTableRow; import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelStackReference; import ch.systemsx.cisd.openbis.dss.generic.server.images.ImageChannelsUtils; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; @@ -238,7 +238,7 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements private FeatureVectorDataset createFeatureVectorDataset(String sessionToken, FeatureVectorDatasetReference dataset, List<String> featureCodes) { - WellFeatureCollection datasetFeatures = + WellFeatureCollection<FeatureTableRow> datasetFeatures = FeatureTableBuilder.fetchDatasetFeatures(Arrays.asList(dataset.getDatasetCode()), featureCodes, getDAO(), getOpenBISService()); List<FeatureVector> featureVectors = new ArrayList<FeatureVector>(); @@ -267,14 +267,14 @@ public class DssServiceRpcScreening extends AbstractDssServiceRpc implements List<String> featureNames) { checkDatasetsAuthorizationForIDatasetIdentifier(sessionToken, datasetWellReferences); - WellFeatureCollection features = + WellFeatureCollection<FeatureTableRow> features = FeatureTableBuilder.fetchWellFeatures(datasetWellReferences, featureNames, dao, getOpenBISService()); return createFeatureVectorList(features); } private List<FeatureVectorWithDescription> createFeatureVectorList( - final WellFeatureCollection features) + final WellFeatureCollection<FeatureTableRow> features) { final List<String> featureCodes = features.getFeatureCodes(); final List<FeatureTableRow> featureTableRows = features.getFeatures(); diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java index 4990d245edbeaa1be13199b4ee2a68fac1a63df0..c5cf8db77c3bbc8dc3f0cb531b9d8f8e95b2b08b 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/ScreeningServer.java @@ -156,7 +156,7 @@ public final class ScreeningServer extends AbstractServer<IScreeningServer> impl { Session session = getSession(sessionToken); return PlateMaterialLocationsLoader.load(session, businessObjectFactory, getDAOFactory(), - materialCriteria, true); + materialCriteria); } public List<WellImageChannelStack> listImageChannelStacks(String sessionToken, diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/FeatureVectorDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/FeatureVectorDatasetLoader.java index 169eafcace92cbee64086c3d76f74d4401d04e55..1e36639bc00c7f76aa89d5887c36e31f972164dd 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/FeatureVectorDatasetLoader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/FeatureVectorDatasetLoader.java @@ -16,16 +16,15 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic; -import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectSortedMap; - import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import ch.systemsx.cisd.openbis.generic.server.business.bo.datasetlister.IDatasetLister; -import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStore; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; import ch.systemsx.cisd.openbis.generic.shared.dto.Session; @@ -45,7 +44,7 @@ class FeatureVectorDatasetLoader extends ImageDatasetLoader private final String featureVectorDatasetTypeCode; // Running state - private List<ExternalData> featureVectorDatasets; + private Collection<ExternalData> featureVectorDatasets; FeatureVectorDatasetLoader(Session session, IScreeningBusinessObjectFactory businessObjectFactory, String homeSpaceOrNull, @@ -57,55 +56,143 @@ class FeatureVectorDatasetLoader extends ImageDatasetLoader featureVectorDatasetTypeCode = ScreeningConstants.IMAGE_ANALYSIS_DATASET_TYPE; } - public List<FeatureVectorDatasetReference> getFeatureVectorDatasets() + public static class FeatureVectorExternalData + { + private final ExternalData featureVectorDataset; + + private final ExternalData imageDatasetOrNull; + + public FeatureVectorExternalData(ExternalData featureVectorDataset, + ExternalData imageDatasetOrNull) + { + this.featureVectorDataset = featureVectorDataset; + this.imageDatasetOrNull = imageDatasetOrNull; + } + + public ExternalData getFeatureVectorDataset() + { + return featureVectorDataset; + } + + public ExternalData tryGetImageDataset() + { + return imageDatasetOrNull; + } + } + + /** enriched with image dataset parents */ + public Collection<ExternalData> getFeatureVectorDatasets() + { + loadAll(); + return featureVectorDatasets; + } + + public List<FeatureVectorDatasetReference> getFeatureVectorDatasetReferences() + { + loadAll(); + return asFeatureVectorDatasetReferences(); + } + + private void loadAll() { // Load the image data sets load(); loadFeatureVectorDatasets(); - return asFeatureVectorDatasets(); } private void loadFeatureVectorDatasets() { - final Long2ObjectSortedMap<ExternalData> featureVectorDatasetSet = - new Long2ObjectLinkedOpenHashMap<ExternalData>(); + final Map<Long, ExternalData> featureVectorDatasetSet = new HashMap<Long, ExternalData>(); IDatasetLister datasetLister = businessObjectFactory.createDatasetLister(session); - for (ExternalData data : getDatasets()) + List<ExternalData> imageDatasets = new ArrayList<ExternalData>(); + for (ExternalData dataset : getDatasets()) { - if (ScreeningUtils.isTypeEqual(data, ScreeningConstants.IMAGE_ANALYSIS_DATASET_TYPE)) + if (ScreeningUtils.isTypeEqual(dataset, ScreeningConstants.IMAGE_ANALYSIS_DATASET_TYPE)) + { + featureVectorDatasetSet.put(dataset.getId(), dataset); + } else if (ScreeningUtils.isTypeEqual(dataset, ScreeningConstants.IMAGE_DATASET_TYPE)) { - featureVectorDatasetSet.put(data.getId(), data); + imageDatasets.add(dataset); } } + List<ExternalData> connectedFeatureVectorDatasets = + listChildrenFeatureVectorDatasets(datasetLister, extractIds(imageDatasets)); + Map<Long, Set<Long>> featureVectorToImageDatasetIdsMap = + datasetLister.listParentIds(extractIds(connectedFeatureVectorDatasets)); + Map<Long, List<ExternalData>> featureVectorToImageDatasetsMap = + createFeatureVectorToImageDatasetsMap(featureVectorToImageDatasetIdsMap, + imageDatasets); // Implementation note: some data sets in this loop may overwrite data from the first loop. // This is intended as we want to keep the parent relationship of the feature vector data // sets, if they exist. - for (ExternalData data : getDatasets()) + for (ExternalData fv : connectedFeatureVectorDatasets) { - if (ScreeningUtils.isTypeEqual(data, ScreeningConstants.IMAGE_DATASET_TYPE)) + List<ExternalData> parentImageDatasets = + featureVectorToImageDatasetsMap.get(fv.getId()); + if (parentImageDatasets != null) { - // TODO 2010-05-26, CR, : This way to access the database one by one is slow if - // there are a large number of image data sets - // Need to add a query to the dataset lister that returns, for a collection of tech - // ids, a child datasets and their parents. - final List<ExternalData> children = - datasetLister.listByParentTechId(new TechId(data.getId())); - for (ExternalData child : children) - { - child.setParents(Collections.singleton(data)); - featureVectorDatasetSet.put(child.getId(), child); - } + fv.setParents(parentImageDatasets); } + featureVectorDatasetSet.put(fv.getId(), fv); } + featureVectorDatasets = featureVectorDatasetSet.values(); + } - featureVectorDatasets = - ScreeningUtils.filterExternalDataByType(featureVectorDatasetSet.values(), - featureVectorDatasetTypeCode); + private List<ExternalData> listChildrenFeatureVectorDatasets(IDatasetLister datasetLister, + Collection<Long> imageDatasetIds) + { + List<ExternalData> datasets = datasetLister.listByParentTechIds(imageDatasetIds); + return ScreeningUtils.filterExternalDataByType(datasets, featureVectorDatasetTypeCode); } - private List<FeatureVectorDatasetReference> asFeatureVectorDatasets() + private static Map<Long/* feature vector dataset id */, List<ExternalData/* image dataset */>> createFeatureVectorToImageDatasetsMap( + Map<Long, Set<Long>> featureVectorToImageDatasetsMap, List<ExternalData> imageDatasets) + { + Map<Long, List<ExternalData>> featureVectorToImageDatasetMap = + new HashMap<Long, List<ExternalData>>(); + for (Entry<Long, Set<Long>> entry : featureVectorToImageDatasetsMap.entrySet()) + { + List<ExternalData> parentImageDatasets = + findDatasetsWithIds(entry.getValue(), imageDatasets); + // NOTE: if a feature vector dataset has more than one image dataset parent, all the + // parents will be ignored. + if (parentImageDatasets.size() == 1) + { + Long featureVectorDatasetId = entry.getKey(); + featureVectorToImageDatasetMap.put(featureVectorDatasetId, parentImageDatasets); + } + } + return featureVectorToImageDatasetMap; + } + + // returns all dataset which have an id contained in the specified id set + private static List<ExternalData> findDatasetsWithIds(Set<Long> datasetIds, + List<ExternalData> datasets) + { + List<ExternalData> found = new ArrayList<ExternalData>(); + for (ExternalData dataset : datasets) + { + if (datasetIds.contains(dataset.getId())) + { + found.add(dataset); + } + } + return found; + } + + private static Collection<Long> extractIds(List<ExternalData> datasets) + { + List<Long> ids = new ArrayList<Long>(); + for (ExternalData dataset : datasets) + { + ids.add(dataset.getId()); + } + return ids; + } + + private List<FeatureVectorDatasetReference> asFeatureVectorDatasetReferences() { List<FeatureVectorDatasetReference> result = new ArrayList<FeatureVectorDatasetReference>(); for (ExternalData externalData : featureVectorDatasets) @@ -115,10 +202,24 @@ class FeatureVectorDatasetLoader extends ImageDatasetLoader return result; } + private static ExternalData tryGetOneParent(ExternalData externalData) + { + Collection<ExternalData> parents = externalData.getParents(); + if (parents != null && parents.size() == 1) + { + return parents.iterator().next(); + } else + { + return null; + } + } + protected FeatureVectorDatasetReference asFeatureVectorDataset(ExternalData externalData) { DataStore dataStore = externalData.getDataStore(); - if (externalData.getParents() == null || externalData.getParents().isEmpty()) + // there should be no more parents than one, we ensure about that earlier + ExternalData parentDataset = tryGetOneParent(externalData); + if (parentDataset == null) { return new FeatureVectorDatasetReference(externalData.getCode(), getDataStoreUrlFromDataStore(dataStore), createPlateIdentifier(externalData), @@ -129,7 +230,6 @@ class FeatureVectorDatasetLoader extends ImageDatasetLoader // Note: this only works reliably because this class sets the parents of the feature // vector data sets itself and sets it to a list with exactly one entry! // (see loadFeatureVectorDatasets() above) - final ExternalData parentDataset = externalData.getParents().iterator().next(); return new FeatureVectorDatasetReference(externalData.getCode(), getDataStoreUrlFromDataStore(dataStore), createPlateIdentifier(parentDataset), createExperimentIdentifier(externalData), extractPlateGeometry(parentDataset), diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ImageDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ImageDatasetLoader.java index 374225ae738437608c76d697ec20c484dbf4b188..119d9ace0666bd0ea76fea538a1fff93b0d00454 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ImageDatasetLoader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ImageDatasetLoader.java @@ -49,25 +49,43 @@ class ImageDatasetLoader extends PlateDatasetLoader /** * Return the image datasets for the specified plates. */ - public List<ImageDatasetReference> getImageDatasets() + public List<ExternalData> getImageDatasets() { load(); return filterImageDatasets(); } - private List<ImageDatasetReference> filterImageDatasets() + /** + * Return the image datasets references for the specified plates. + */ + public List<ImageDatasetReference> getImageDatasetReferences() + { + return asImageDatasetReferences(getImageDatasets()); + } + + private List<ExternalData> filterImageDatasets() { - List<ImageDatasetReference> result = new ArrayList<ImageDatasetReference>(); + List<ExternalData> result = new ArrayList<ExternalData>(); for (ExternalData externalData : getDatasets()) { if (ScreeningUtils.isTypeEqual(externalData, ScreeningConstants.IMAGE_DATASET_TYPE)) { - result.add(asImageDataset(externalData)); + result.add(externalData); } } return result; } + private List<ImageDatasetReference> asImageDatasetReferences(List<ExternalData> imageDatasets) + { + List<ImageDatasetReference> references = new ArrayList<ImageDatasetReference>(); + for (ExternalData imageDataset : imageDatasets) + { + references.add(asImageDataset(imageDataset)); + } + return references; + } + protected ImageDatasetReference asImageDataset(ExternalData externalData) { DataStore dataStore = externalData.getDataStore(); diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateDatasetLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateDatasetLoader.java index 31de9e17692dab1add7ab93341e3c9cdc803d778..776e7ad244bb3d8dc203264cb521612d53dcfb24 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateDatasetLoader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateDatasetLoader.java @@ -190,7 +190,7 @@ class PlateDatasetLoader return new PlateIdentifier(plateCode, spaceCodeOrNull, sample.getPermId()); } - protected ExperimentIdentifier createExperimentIdentifier(ExternalData parentDataset) + protected static ExperimentIdentifier createExperimentIdentifier(ExternalData parentDataset) { return asExperimentIdentifier(parentDataset.getExperiment()); } @@ -282,7 +282,7 @@ class PlateDatasetLoader return sampleIds; } - protected String getDataStoreUrlFromDataStore(DataStore dataStore) + protected static String getDataStoreUrlFromDataStore(DataStore dataStore) { String datastoreUrl = dataStore.getDownloadUrl(); // The url objained form a DataStore object is the *download* url. Convert this to the diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateMaterialLocationsLoader.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateMaterialLocationsLoader.java index 9c8850e2c7ed364f646c109ad847405304f99904..cd88d1cb6c18a104ffa87e23218b41ae157c61cb 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateMaterialLocationsLoader.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateMaterialLocationsLoader.java @@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic; import java.sql.Connection; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -31,11 +32,13 @@ import net.lemnik.eodsql.DataIterator; import net.lemnik.eodsql.QueryTool; import org.apache.commons.lang.ArrayUtils; +import org.apache.log4j.Logger; import ch.rinn.restrictions.Friend; import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.common.logging.LogCategory; +import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.openbis.generic.server.business.bo.common.DatabaseContextUtils; -import ch.systemsx.cisd.openbis.generic.server.business.bo.datasetlister.IDatasetLister; import ch.systemsx.cisd.openbis.generic.server.business.bo.materiallister.IMaterialLister; import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory; import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; @@ -56,18 +59,18 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.MaterialTypePropertyTypePE; import ch.systemsx.cisd.openbis.generic.shared.dto.Session; import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory; import ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.IScreeningQuery; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.DatasetImagesReference; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.DatasetReference; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ExperimentReference; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateImageParameters; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMaterialsSearchCriteria; -import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; -import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellContent; -import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMaterialsSearchCriteria.ExperimentSearchCriteria; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMaterialsSearchCriteria.MaterialSearchCodesCriteria; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMaterialsSearchCriteria.MaterialSearchCriteria; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMaterialsSearchCriteria.SingleExperimentSearchCriteria; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellContent; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.WellLocation; /** * Loades selected wells content: metadata and (if available) image dataset and feature vectors. @@ -77,6 +80,9 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.PlateMaterials @Friend(toClasses = IScreeningQuery.class) public class PlateMaterialLocationsLoader { + private final static Logger operationLog = LogFactory.getLogger(LogCategory.OPERATION, + PlateMaterialLocationsLoader.class); + /** * Finds wells containing the specified material and belonging to the specified experiment. * Loads wells content: metadata and (if available) image dataset and feature vectors. @@ -91,10 +97,10 @@ public class PlateMaterialLocationsLoader public static List<WellContent> load(Session session, IScreeningBusinessObjectFactory businessObjectFactory, IDAOFactory daoFactory, - PlateMaterialsSearchCriteria materialCriteria, boolean enrichWithImages) + PlateMaterialsSearchCriteria materialCriteria) { return new PlateMaterialLocationsLoader(session, businessObjectFactory, daoFactory) - .getPlateLocations(materialCriteria, enrichWithImages); + .getPlateLocations(materialCriteria, true); } /** loads wells metadata, but no information about image or image analysis datasets */ @@ -153,52 +159,186 @@ public class PlateMaterialLocationsLoader private List<WellContent> enrichWithDatasets(List<WellContent> locations) { - List<ExternalData> imageDatasets = loadImageDatasets(locations); - Map<Long/* plate id */, List<ExternalData>> plateToDatasetMap = - createPlateToDatasetMap(imageDatasets); + Collection<PlateIdentifier> plates = extractPlates(locations); + FeatureVectorDatasetLoader datasetsRetriever = + new FeatureVectorDatasetLoader(session, businessObjectFactory, null, plates); + Collection<ExternalData> imageDatasets = datasetsRetriever.getImageDatasets(); Map<String, PlateImageParameters> imageParams = loadImagesReport(imageDatasets); - return enrichWithImages(locations, plateToDatasetMap, imageParams); + + // TODO 2010-09-07, Tomasz Pylak: uncomment this when showing fetures in Reviewing Panel is + // implemented + // Collection<ExternalData> featureVectorDatasets = + // datasetsRetriever.getFeatureVectorDatasets(); + // Collection<ExternalData> childlessImageDatasets = + // selectChildlessImageDatasets(imageDatasets, featureVectorDatasets); + // + // Map<Long/* plate id */, List<ExternalData>> plateToChildlessImageDatasetMap = + // createPlateToDatasetMap(childlessImageDatasets); + // Map<Long/* plate id */, List<ExternalData>> plateToFeatureVectoreDatasetMap = + // createPlateToDatasetMap(featureVectorDatasets); + // + // return enrichWithDatasets(locations, plateToChildlessImageDatasetMap, + // plateToFeatureVectoreDatasetMap, imageParams); + + return enrichWithDatasets(locations, createPlateToDatasetMap(imageDatasets), + new HashMap<Long, List<ExternalData>>(), imageParams); } - private static List<WellContent> enrichWithImages(List<WellContent> wellContents, - Map<Long/* plate id */, List<ExternalData>> plateToDatasetMap, - Map<String, PlateImageParameters> imageParams) + @SuppressWarnings("unused") + private static Collection<ExternalData> selectChildlessImageDatasets( + Collection<ExternalData> imageDatasets, Collection<ExternalData> featureVectorDatasets) { - List<WellContent> wellsWithImages = new ArrayList<WellContent>(); - for (WellContent wellContent : wellContents) + Collection<ExternalData> childlessImageDatasets = new ArrayList<ExternalData>(); + Set<String> parentImageDatasetCodes = extractParentDatasetCodes(featureVectorDatasets); + for (ExternalData imageDataset : imageDatasets) { - List<ExternalData> datasets = plateToDatasetMap.get(wellContent.getPlate().getId()); - boolean imagesExist = false; - // there can be more than one dataset with images for each well - in such a case we will - // have one well content duplicated for each dataset - if (datasets != null) + if (parentImageDatasetCodes.contains(imageDataset.getCode()) == false) { - for (ExternalData dataset : datasets) + childlessImageDatasets.add(imageDataset); + } + } + return childlessImageDatasets; + } + + private static Set<String> extractParentDatasetCodes(Collection<ExternalData> datasets) + { + Set<String> codes = new HashSet<String>(); + for (ExternalData dataset : datasets) + { + Collection<ExternalData> parents = dataset.getParents(); + if (parents != null) + { + for (ExternalData parent : parents) { - PlateImageParameters imageParameters = imageParams.get(dataset.getCode()); - if (imageParameters != null) - { - DatasetReference datasetReference = - ScreeningUtils.createDatasetReference(dataset); - DatasetImagesReference wellImages = - DatasetImagesReference.create(datasetReference, imageParameters); - WellContent wellWithImages = wellContent.cloneWithImages(wellImages); - wellsWithImages.add(wellWithImages); - imagesExist = true; - } + codes.add(parent.getCode()); } } + } + return codes; + } + + private static Collection<PlateIdentifier> extractPlates(List<WellContent> locations) + { + Collection<PlateIdentifier> plates = new ArrayList<PlateIdentifier>(); + for (WellContent location : locations) + { + plates.add(PlateIdentifier.createFromPermId(location.getPlate().getPermId())); + } + return plates; + } + + /** + * Connects wells with datasets. + */ + private static List<WellContent> enrichWithDatasets(List<WellContent> wellContents, + Map<Long/* plate id */, List<ExternalData>> plateToChildlessImageDatasetMap, + Map<Long/* plate id */, List<ExternalData>> plateToFeatureVectoreDatasetMap, + Map<String, PlateImageParameters> imageParams) + { + List<WellContent> wellsWithDatasets = new ArrayList<WellContent>(); + for (WellContent wellContent : wellContents) + { + List<WellContent> clonedWellContents = + enrichWithDatasetReferences(wellContent, plateToChildlessImageDatasetMap, + plateToFeatureVectoreDatasetMap, imageParams); // if there are no datasets for the well content, we add it without images - if (imagesExist == false) + if (clonedWellContents.isEmpty()) + { + wellsWithDatasets.add(wellContent); + } else { - wellsWithImages.add(wellContent); + wellsWithDatasets.addAll(clonedWellContents); } } - return wellsWithImages; + wellsWithDatasets = enrichWithFeatureVectors(wellsWithDatasets); + return wellsWithDatasets; + } + + private static List<WellContent> enrichWithFeatureVectors(List<WellContent> wellsWithDatasets) + { + // TODO 2010-09-07, Tomasz Pylak: Enrich each WellContent with feature values. + // WellFeatureCollection<FeatureVectorValues> featureVectors = + // FeatureTableBuilder.fetchWellFeatureValues(references, dao, service); + // return enrichWithFeatureVectors(wellsWithDatasets, featureVectors); + return wellsWithDatasets; + } + + /** + * Connects one WellContent with dataset references.<br> + * We want to present all the data to the user, so if a well has several feature vector + * datasets, it will be cloned several times. By connecting to feature vector datasets we are + * possibly connecting to image datasets as well.<br> + * Additionally a join with childless image datasets has to be performed. + */ + private static List<WellContent> enrichWithDatasetReferences(WellContent wellContent, + Map<Long, List<ExternalData>> plateToChildlessImageDatasetMap, + Map<Long, List<ExternalData>> plateToFeatureVectoreDatasetMap, + Map<String, PlateImageParameters> imageParams) + { + Long plateId = wellContent.getPlate().getId(); + List<WellContent> clonedWellContents = new ArrayList<WellContent>(); + + List<ExternalData> featureVectoreDatasets = plateToFeatureVectoreDatasetMap.get(plateId); + if (featureVectoreDatasets != null) + { + for (ExternalData featureVectoreDataset : featureVectoreDatasets) + { + DatasetReference featureVectoreDatasetReference = + ScreeningUtils.createDatasetReference(featureVectoreDataset); + DatasetImagesReference imagesDatasetReference = + tryGetImageDatasetReference(featureVectoreDataset, imageParams); + clonedWellContents.add(wellContent.cloneWithDatasets(imagesDatasetReference, + featureVectoreDatasetReference)); + } + } + + // there can be more than one dataset with images for each well - in such a case we will + // have one well content duplicated for each dataset + List<ExternalData> childlessImageDatasets = plateToChildlessImageDatasetMap.get(plateId); + if (childlessImageDatasets != null) + { + for (ExternalData childlessImageDataset : childlessImageDatasets) + { + DatasetImagesReference imagesDatasetReference = + createDatasetImagesReference(childlessImageDataset, imageParams); + clonedWellContents.add(wellContent.cloneWithDatasets(imagesDatasetReference, null)); + } + } + return clonedWellContents; + } + + private static DatasetImagesReference tryGetImageDatasetReference( + ExternalData featureVectoreDataset, Map<String, PlateImageParameters> imageParams) + { + Collection<ExternalData> parents = featureVectoreDataset.getParents(); + if (parents != null && parents.size() == 1) + { + ExternalData imageDataset = parents.iterator().next(); + return createDatasetImagesReference(imageDataset, imageParams); + } else + { + return null; + } + } + + private static DatasetImagesReference createDatasetImagesReference(ExternalData imageDataset, + Map<String, PlateImageParameters> imageParams) + { + PlateImageParameters imageParameters = imageParams.get(imageDataset.getCode()); + if (imageParameters != null) + { + return DatasetImagesReference.create( + ScreeningUtils.createDatasetReference(imageDataset), imageParameters); + } else + { + operationLog.error("Cannot find image parameters for dataset: " + + imageDataset.getCode() + ". It will not be displayed"); + return null; + } } private static Map<Long/* sample id */, List<ExternalData>> createPlateToDatasetMap( - List<ExternalData> datasets) + Collection<ExternalData> datasets) { Map<Long, List<ExternalData>> map = new HashMap<Long, List<ExternalData>>(); for (ExternalData dataset : datasets) @@ -221,7 +361,7 @@ public class PlateMaterialLocationsLoader } private Map<String/* dataset code */, PlateImageParameters> loadImagesReport( - List<ExternalData> imageDatasets) + Collection<ExternalData> imageDatasets) { List<PlateImageParameters> imageParameters = new ArrayList<PlateImageParameters>(); for (ExternalData dataSet : imageDatasets) @@ -242,28 +382,6 @@ public class PlateMaterialLocationsLoader return map; } - private List<ExternalData> loadImageDatasets(List<WellContent> locations) - { - Set<Long> plateIds = extractPlateIds(locations); - - IDatasetLister datasetLister = businessObjectFactory.createDatasetLister(session); - List<ExternalData> imageDatasets = datasetLister.listBySampleIds(plateIds); - imageDatasets = - ScreeningUtils.filterExternalDataByType(imageDatasets, - ScreeningConstants.IMAGE_DATASET_TYPE); - return imageDatasets; - } - - private static Set<Long> extractPlateIds(List<WellContent> locations) - { - Set<Long> ids = new HashSet<Long>(); - for (WellContent loc : locations) - { - ids.add(loc.getPlate().getId()); - } - return ids; - } - private List<WellContent> loadLocations(PlateMaterialsSearchCriteria materialCriteria) { DataIterator<ch.systemsx.cisd.openbis.plugin.screening.server.dataaccess.WellContent> locations; @@ -403,7 +521,7 @@ public class PlateMaterialLocationsLoader return wellLocations; } - private List<Material> getMaterials(List<WellContent> wellLocations) + private static List<Material> getMaterials(List<WellContent> wellLocations) { List<Material> materials = new ArrayList<Material>(); for (WellContent wc : wellLocations) diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java index 2d7102f23a45c158a52d8a72a9e39f6796f6a976..808cbd9d69fba9c9660b187d5623670822476af0 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImpl.java @@ -102,9 +102,9 @@ public class ScreeningApiImpl List<? extends PlateIdentifier> plates) { FeatureVectorDatasetLoader datasetRetriever = - new FeatureVectorDatasetLoader(session, businessObjectFactory, session - .tryGetHomeGroupCode(), plates); - List<FeatureVectorDatasetReference> result = datasetRetriever.getFeatureVectorDatasets(); + new FeatureVectorDatasetLoader(session, businessObjectFactory, + session.tryGetHomeGroupCode(), plates); + List<FeatureVectorDatasetReference> result = datasetRetriever.getFeatureVectorDatasetReferences(); return result; } @@ -112,7 +112,7 @@ public class ScreeningApiImpl public List<ImageDatasetReference> listImageDatasets(List<? extends PlateIdentifier> plates) { return new ImageDatasetLoader(session, businessObjectFactory, - session.tryGetHomeGroupCode(), plates).getImageDatasets(); + session.tryGetHomeGroupCode(), plates).getImageDatasetReferences(); } public List<Plate> listPlates() @@ -154,8 +154,8 @@ public class ScreeningApiImpl final String sampleSpaceCode = (sampleSpace != null) ? sampleSpace.getCode() : null; final Space experimentSpace = project.getSpace(); final ExperimentIdentifier experimentId = - new ExperimentIdentifier(experiment.getCode(), project.getCode(), experimentSpace - .getCode(), experiment.getPermId()); + new ExperimentIdentifier(experiment.getCode(), project.getCode(), + experimentSpace.getCode(), experiment.getPermId()); return new Plate(sample.getCode(), sampleSpaceCode, sample.getPermId(), experimentId); } @@ -250,34 +250,41 @@ public class ScreeningApiImpl throw UserFailureException.fromTemplate("Material '%s' does not exist", materialIdentifier.getAugmentedCode()); } - final List<WellContent> wellContent; + final List<WellContent> wellContents; final ExperimentIdentifier fullExperimentIdentifier = getExperimentIdentifierFromDB(experimentIdentifier); - wellContent = + wellContents = PlateMaterialLocationsLoader.load(session, businessObjectFactory, daoFactory, new TechId(materialOrNull.getId()), fullExperimentIdentifier.getPermId(), false); if (findDatasets) { - final Set<Plate> plates = new HashSet<Plate>(wellContent.size()); - for (WellContent w : wellContent) - { - plates.add(asPlate(fullExperimentIdentifier, w)); - } + final Set<Plate> plates = extractPlates(wellContents, fullExperimentIdentifier); final FeatureVectorDatasetLoader datasetRetriever = - new FeatureVectorDatasetLoader(session, businessObjectFactory, session - .tryGetHomeGroupCode(), plates); - final List<ImageDatasetReference> imageDatasets = datasetRetriever.getImageDatasets(); + new FeatureVectorDatasetLoader(session, businessObjectFactory, + session.tryGetHomeGroupCode(), plates); + final List<ImageDatasetReference> imageDatasets = datasetRetriever.getImageDatasetReferences(); final List<FeatureVectorDatasetReference> featureVectorDatasets = - datasetRetriever.getFeatureVectorDatasets(); + datasetRetriever.getFeatureVectorDatasetReferences(); - return asPlateWellReferences(fullExperimentIdentifier, wellContent, + return asPlateWellReferences(fullExperimentIdentifier, wellContents, createPlateToDatasetsMap(imageDatasets, featureVectorDatasets)); } else { - return asPlateWellReferences(fullExperimentIdentifier, wellContent, Collections - .<String, DatasetReferenceHolder> emptyMap()); + return asPlateWellReferences(fullExperimentIdentifier, wellContents, + Collections.<String, DatasetReferenceHolder> emptyMap()); + } + } + + private static Set<Plate> extractPlates(final List<WellContent> wellContents, + final ExperimentIdentifier fullExperimentIdentifier) + { + final Set<Plate> plates = new HashSet<Plate>(wellContents.size()); + for (WellContent wellContent : wellContents) + { + plates.add(asPlate(fullExperimentIdentifier, wellContent)); } + return plates; } public List<PlateWellReferenceWithDatasets> listPlateWells( @@ -294,8 +301,8 @@ public class ScreeningApiImpl materialIdentifier.getAugmentedCode()); } final List<WellContent> wellContent = - PlateMaterialLocationsLoader.loadOnlyMetadata(session, businessObjectFactory, daoFactory, - new TechId(materialOrNull.getId())); + PlateMaterialLocationsLoader.loadOnlyMetadata(session, businessObjectFactory, + daoFactory, new TechId(materialOrNull.getId())); if (findDatasets) { @@ -305,18 +312,18 @@ public class ScreeningApiImpl plates.add(asPlate(w)); } final FeatureVectorDatasetLoader datasetRetriever = - new FeatureVectorDatasetLoader(session, businessObjectFactory, session - .tryGetHomeGroupCode(), plates); - final List<ImageDatasetReference> imageDatasets = datasetRetriever.getImageDatasets(); + new FeatureVectorDatasetLoader(session, businessObjectFactory, + session.tryGetHomeGroupCode(), plates); + final List<ImageDatasetReference> imageDatasets = datasetRetriever.getImageDatasetReferences(); final List<FeatureVectorDatasetReference> featureVectorDatasets = - datasetRetriever.getFeatureVectorDatasets(); + datasetRetriever.getFeatureVectorDatasetReferences(); - return asPlateWellReferences(wellContent, createPlateToDatasetsMap(imageDatasets, - featureVectorDatasets)); + return asPlateWellReferences(wellContent, + createPlateToDatasetsMap(imageDatasets, featureVectorDatasets)); } else { - return asPlateWellReferences(wellContent, Collections - .<String, DatasetReferenceHolder> emptyMap()); + return asPlateWellReferences(wellContent, + Collections.<String, DatasetReferenceHolder> emptyMap()); } } @@ -330,8 +337,8 @@ public class ScreeningApiImpl for (PlateIdentifier plate : plates) { result.add(toPlateWellMaterialMapping(plate, materialTypeIdentifierOrNull, - getPlateGeometry(query, plate), getPlateMapping(query, plate, - materialTypeIdentifierOrNull))); + getPlateGeometry(query, plate), + getPlateMapping(query, plate, materialTypeIdentifierOrNull))); } return result; } @@ -416,8 +423,8 @@ public class ScreeningApiImpl { if (plate.getPermId() == null) { - return query.getPlateMappingForMaterialType(plate.tryGetSpaceCode(), plate - .getPlateCode(), materialTypeIdentifierOrNull.getMaterialTypeCode()); + return query.getPlateMappingForMaterialType(plate.tryGetSpaceCode(), + plate.getPlateCode(), materialTypeIdentifierOrNull.getMaterialTypeCode()); } else { return query.getPlateMappingForMaterialType(plate.getPermId(), @@ -575,8 +582,7 @@ public class ScreeningApiImpl { return (o1.getExperimentPlateIdentifier().getAugmentedCode() + ":" + o1 .getWellPosition()).compareTo(o2.getExperimentPlateIdentifier() - .getAugmentedCode() - + ":" + o2.getWellPosition()); + .getAugmentedCode() + ":" + o2.getWellPosition()); } }); return plateWellReferences; @@ -599,8 +605,7 @@ public class ScreeningApiImpl { return (o1.getExperimentPlateIdentifier().getAugmentedCode() + ":" + o1 .getWellPosition()).compareTo(o2.getExperimentPlateIdentifier() - .getAugmentedCode() - + ":" + o2.getWellPosition()); + .getAugmentedCode() + ":" + o2.getWellPosition()); } }); return plateWellReferences; diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/FeatureVectorDatasetWellReference.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/FeatureVectorDatasetWellReference.java index 4237ba47b38de4bc6160c425df529a9c2abc3c58..123aff3186c66ad00c1991903c7f754b0fa14c25 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/FeatureVectorDatasetWellReference.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/api/v1/dto/FeatureVectorDatasetWellReference.java @@ -39,6 +39,14 @@ public class FeatureVectorDatasetWellReference extends FeatureVectorDatasetRefer this.wellPosition = wellPosition; } + public FeatureVectorDatasetWellReference(FeatureVectorDatasetReference fvdr, + WellPosition wellPosition) + { + this(fvdr.getDatasetCode(), fvdr.getDatastoreServerUrl(), fvdr.getPlate(), fvdr + .getExperimentIdentifier(), fvdr.getPlateGeometry(), fvdr.getRegistrationDate(), + fvdr.getParentImageDataset(), wellPosition); + } + public FeatureVectorDatasetWellReference(String datasetCode, String datastoreServerUrl, PlateIdentifier plate, ExperimentIdentifier experimentIdentifier, Geometry plateGeometry, Date registrationDate, diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/WellContent.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/WellContent.java index d5ae969848daf776b3671f8adfb7843d84cdc2e2..adee923c87ab85ee8fe0b944f1cb36a37a83d9b1 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/WellContent.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/shared/basic/dto/WellContent.java @@ -37,11 +37,20 @@ public class WellContent implements IsSerializable private ExperimentReference experiment; - // a pointer to a material which was being searched for inside a well + // Material which was being searched for inside a well. Enriched with properties. private Material materialContent; - // contains only images for this well, null if no images have been acquired - private DatasetImagesReference imagesOrNull; + // dataset which contains images for this well, null if no images have been acquired + private DatasetImagesReference imagesDatasetOrNull; + + // dataset which contains feature vectors for this well, null if images have not been analyzed + private DatasetReference featureVectorDatasetOrNull; + + // Feature vector values, null if images have not been analyzed. + // Some features may not be available, then the value is Float.NaN. + // External data structure should be used to figure out which value corresponds to which + // feature. + private float[] featureVectorValuesOrNull; // GWT only @SuppressWarnings("unused") @@ -81,7 +90,17 @@ public class WellContent implements IsSerializable public DatasetImagesReference tryGetImageDataset() { - return imagesOrNull; + return imagesDatasetOrNull; + } + + public DatasetReference tryGetFeatureVectorDataset() + { + return featureVectorDatasetOrNull; + } + + public float[] tryGetFeatureVectorValues() + { + return featureVectorValuesOrNull; } public ExperimentReference getExperiment() @@ -89,11 +108,23 @@ public class WellContent implements IsSerializable return experiment; } - public WellContent cloneWithImages(DatasetImagesReference images) + public WellContent cloneWithDatasets(DatasetImagesReference imagesOrNull, + DatasetReference featureVectorOrNull) + { + WellContent clone = + new WellContent(locationOrNull, well, plate, experiment, materialContent); + clone.imagesDatasetOrNull = imagesOrNull; + clone.featureVectorDatasetOrNull = featureVectorOrNull; + return clone; + } + + public WellContent cloneWithDatasets(float[] values) { WellContent clone = new WellContent(locationOrNull, well, plate, experiment, materialContent); - clone.imagesOrNull = images; + clone.imagesDatasetOrNull = imagesDatasetOrNull; + clone.featureVectorDatasetOrNull = featureVectorDatasetOrNull; + clone.featureVectorValuesOrNull = values; return clone; } diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableBuilderTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableBuilderTest.java index 06aeb1158b05a5a2d69735be0aa9597ffce1a38e..0fa3a7a720dcbbc7996e665e5277ad73ff055c3b 100644 --- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableBuilderTest.java +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/dss/generic/server/FeatureTableBuilderTest.java @@ -27,6 +27,7 @@ import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import ch.systemsx.cisd.openbis.dss.generic.server.featurevectors.FeatureTableRow; import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService; import ch.systemsx.cisd.openbis.dss.generic.shared.utils.CodeAndLabel; import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier; diff --git a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImplTest.java b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImplTest.java index c7d94e81902798a8405450fc5b5ede6c7a667b6d..c3d42709a24ce5489adbef95871c5ac66ba9ed13 100644 --- a/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImplTest.java +++ b/screening/sourceTest/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningApiImplTest.java @@ -19,7 +19,11 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import org.jmock.Expectations; import org.testng.annotations.BeforeMethod; @@ -27,7 +31,6 @@ import org.testng.annotations.Test; import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.openbis.generic.shared.AbstractServerTestCase; -import ch.systemsx.cisd.openbis.generic.shared.basic.TechId; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataStore; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityProperty; @@ -81,8 +84,8 @@ public class ScreeningApiImplTest extends AbstractServerTestCase one(screeningBOFactory).createDatasetLister(SESSION); will(returnValue(datasetLister)); one(datasetLister).listBySampleIds(with(Arrays.asList((long) 1))); - will(returnValue(Arrays.asList(imageDataSet(p1, "1", 1), imageAnalysisDataSet( - p1, "2", 2)))); + will(returnValue(Arrays.asList(imageDataSet(p1, "1", 1), + imageAnalysisDataSet(p1, "2", 2)))); } }); @@ -129,8 +132,8 @@ public class ScreeningApiImplTest extends AbstractServerTestCase fail("UserFailureException expected"); } catch (UserFailureException ex) { - assertEquals("Sample '/p1' has no property " + ScreeningConstants.PLATE_GEOMETRY, ex - .getMessage()); + assertEquals("Sample '/p1' has no property " + ScreeningConstants.PLATE_GEOMETRY, + ex.getMessage()); } context.assertIsSatisfied(); } @@ -178,12 +181,22 @@ public class ScreeningApiImplTest extends AbstractServerTestCase exactly(2).of(screeningBOFactory).createDatasetLister(SESSION); will(returnValue(datasetLister)); - one(datasetLister).listBySampleIds(with(Arrays.asList((long) 1))); - will(returnValue(Arrays.asList(imageDataSet(p1, "1", 1), imageAnalysisDataSet( - p1, "2", 2)))); - - one(datasetLister).listByParentTechId(new TechId(1)); - will(returnValue(Arrays.asList(imageAnalysisDataSet(null, "3", 3)))); + long imageDatasetId = 1; + one(datasetLister).listBySampleIds(with(Arrays.asList(imageDatasetId))); + will(returnValue(Arrays.asList( + imageDataSet(p1, "" + imageDatasetId, imageDatasetId), + imageAnalysisDataSet(p1, "2", 2)))); + + one(datasetLister).listByParentTechIds(Arrays.asList(imageDatasetId)); + long analysisDatasetId = 3; + will(returnValue(Arrays.asList(imageAnalysisDataSet(null, "" + + analysisDatasetId, analysisDatasetId)))); + + one(datasetLister).listParentIds(Arrays.asList(analysisDatasetId)); + Map<Long, Set<Long>> parentToChildrenMap = new HashMap<Long, Set<Long>>(); + parentToChildrenMap.put(analysisDatasetId, + new HashSet<Long>(Arrays.asList(imageDatasetId))); + will(returnValue(parentToChildrenMap)); } });