From fd709509bada2ceb36011ce5c153656d4a47549b Mon Sep 17 00:00:00 2001 From: cramakri <cramakri> Date: Thu, 27 May 2010 07:42:53 +0000 Subject: [PATCH] LMS-1544 Improved performace of listImages and listFeatureVectors. SVN: 16139 --- .../screening/server/ScreeningServer.java | 3 +- .../logic/FeatureVectorDatasetLoader.java | 108 ++++++++ .../server/logic/ImageDatasetLoader.java | 72 +++++ .../server/logic/PlateDatasetLoader.java | 258 ++++++++++++++++++ .../server/logic/ScreeningApiImpl.java | 214 +-------------- .../server/logic/ScreeningUtils.java | 20 ++ .../server/logic/ScreeningApiImplTest.java | 58 ++-- 7 files changed, 499 insertions(+), 234 deletions(-) create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/FeatureVectorDatasetLoader.java create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ImageDatasetLoader.java create mode 100644 screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateDatasetLoader.java 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 88134d36778..8c8f91858ce 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 @@ -199,7 +199,8 @@ public final class ScreeningServer extends AbstractServer<IScreeningServer> impl private ScreeningApiImpl createScreeningApiImpl(String sessionToken) { final Session session = getSession(sessionToken); - return new ScreeningApiImpl(session, businessObjectFactory, getDAOFactory()); + return new ScreeningApiImpl(session, businessObjectFactory, getDAOFactory(), + getDataStoreBaseURL()); } public void logoutScreening(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 new file mode 100644 index 00000000000..f1fc3a5e4a9 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/FeatureVectorDatasetLoader.java @@ -0,0 +1,108 @@ +/* + * 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.plugin.screening.server.logic; + +import java.util.ArrayList; +import java.util.List; + +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; +import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; + +/** + * @author Chandrasekhar Ramakrishnan + */ +class FeatureVectorDatasetLoader extends ImageDatasetLoader +{ + // TODO 2010-05-27, CR : See PlateDatasetLoader todo comment + + // Parameter state + private final String featureVectorDatasetTypeCode; + + // Running state + private List<ExternalData> featureVectorDatasets; + + FeatureVectorDatasetLoader(Session session, + IScreeningBusinessObjectFactory businessObjectFactory, String dataStoreBaseURL, + List<? extends PlateIdentifier> plates) + { + super(session, businessObjectFactory, dataStoreBaseURL, plates); + featureVectorDatasetTypeCode = ScreeningConstants.IMAGE_ANALYSIS_DATASET_TYPE; + } + + public List<FeatureVectorDatasetReference> getFeatureVectorDatasets() + { + // Load the image data sets + load(); + loadFeatureVectorDatasets(); + return asFeatureVectorDatasets(); + } + + private void loadFeatureVectorDatasets() + { + // TODO 2010-05-26, CR, : This 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. + featureVectorDatasets = new ArrayList<ExternalData>(); + IDatasetLister datasetLister = + businessObjectFactory.createDatasetLister(session, dataStoreBaseURL); + + for (ExternalData data : getDatasets()) + { + List<ExternalData> children = + datasetLister.listByParentTechId(new TechId(data.getId())); + ArrayList<ExternalData> parentList = new ArrayList<ExternalData>(); + parentList.add(data); + for (ExternalData child : children) + { + child.setParents(parentList); + } + featureVectorDatasets.addAll(children); + } + + featureVectorDatasets = + ScreeningUtils.filterExternalDataByType(featureVectorDatasets, + featureVectorDatasetTypeCode); + } + + private List<FeatureVectorDatasetReference> asFeatureVectorDatasets() + { + List<FeatureVectorDatasetReference> result = new ArrayList<FeatureVectorDatasetReference>(); + for (ExternalData externalData : featureVectorDatasets) + { + result.add(asFeatureVectorDataset(externalData)); + } + return result; + } + + protected FeatureVectorDatasetReference asFeatureVectorDataset(ExternalData externalData) + { + DataStore dataStore = externalData.getDataStore(); + ExternalData parentDataset = externalData.getParents().iterator().next(); + return new FeatureVectorDatasetReference(externalData.getCode(), + dataStore.getDownloadUrl(), createPlateIdentifier(parentDataset), + extractPlateGeometry(parentDataset), externalData.getRegistrationDate(), + asImageDataset(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 new file mode 100644 index 00000000000..2dee96c43c8 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ImageDatasetLoader.java @@ -0,0 +1,72 @@ +/* + * 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.plugin.screening.server.logic; + +import java.util.ArrayList; +import java.util.List; + +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; +import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageDatasetReference; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; + +/** + * Utility class for loading image datasets. + * + * @author Chandrasekhar Ramakrishnan + */ +class ImageDatasetLoader extends PlateDatasetLoader +{ + // TODO 2010-05-27, CR : See PlateDatasetLoader todo comment + + ImageDatasetLoader(Session session, IScreeningBusinessObjectFactory businessObjectFactory, + String dataStoreBaseURL, List<? extends PlateIdentifier> plates) + { + super(session, businessObjectFactory, dataStoreBaseURL, plates, + ScreeningConstants.IMAGE_DATASET_TYPE); + } + + /** + * Return the image datasets for the specified plates. + */ + public List<ImageDatasetReference> getImageDatasets() + { + load(); + return asImageDatasets(); + } + + private List<ImageDatasetReference> asImageDatasets() + { + List<ImageDatasetReference> result = new ArrayList<ImageDatasetReference>(); + for (ExternalData externalData : getDatasets()) + { + result.add(asImageDataset(externalData)); + } + return result; + } + + protected ImageDatasetReference asImageDataset(ExternalData externalData) + { + DataStore dataStore = externalData.getDataStore(); + return new ImageDatasetReference(externalData.getCode(), dataStore.getDownloadUrl(), + createPlateIdentifier(externalData), extractPlateGeometry(externalData), + externalData.getRegistrationDate()); + } +} 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 new file mode 100644 index 00000000000..891e0309cf7 --- /dev/null +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/PlateDatasetLoader.java @@ -0,0 +1,258 @@ +package ch.systemsx.cisd.openbis.plugin.screening.server.logic; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import ch.systemsx.cisd.common.exceptions.UserFailureException; +import ch.systemsx.cisd.openbis.generic.server.business.bo.datasetlister.IDatasetLister; +import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListOrSearchSampleCriteria; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.PropertyType; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Space; +import ch.systemsx.cisd.openbis.generic.shared.dto.Session; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier; +import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier; +import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; +import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifier; +import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; + +/** + * A helper class for retrieving data sets assocaiated with plates. + * + * @author Chandrasekhar Ramakrishnan + */ +class PlateDatasetLoader +{ + // TODO 2010-05-27, CR : This class and its subclasses should be refactored. The subclasses + // should become independent and use the dataset loader, instead of being dataset loaders. + + // Infrastructure state + protected final Session session; + + protected final IScreeningBusinessObjectFactory businessObjectFactory; + + protected final String dataStoreBaseURL; + + // Parameter state + private final List<? extends PlateIdentifier> plates; + + private final String datasetTypeCode; + + // Running state + private List<Sample> samples; + + private List<ExternalData> datasets; + + private HashMap<SampleIdentifier, Sample> samplesByIdentifier; + + private HashMap<Long, Sample> samplesById; + + PlateDatasetLoader(Session session, IScreeningBusinessObjectFactory businessObjectFactory, + String dataStoreBaseURL, List<? extends PlateIdentifier> plates, String datasetTypeCode) + { + this.session = session; + this.businessObjectFactory = businessObjectFactory; + this.dataStoreBaseURL = dataStoreBaseURL; + this.plates = plates; + this.datasetTypeCode = datasetTypeCode; + } + + protected List<ExternalData> getDatasets() + { + return datasets; + } + + /** + * Loads the samples and datasets. Call the method before calling {@link #getDatasets()}. + */ + protected void load() + { + loadSamples(); + loadDatasets(); + } + + private void loadSamples() + { + String[] sampleCodesArray = extractSampleCodes(); + ListOrSearchSampleCriteria criteria = new ListOrSearchSampleCriteria(sampleCodesArray); + ISampleLister sampleLister = businessObjectFactory.createSampleLister(session); + samples = sampleLister.list(criteria); + // After loading the samples, we need to initialize the maps because other methods rely + // on this. + initializeSampleMaps(); + filterSamplesByPlateIdentifiers(); + } + + private void loadDatasets() + { + List<Long> sampleIds = extractSampleIds(); + IDatasetLister datasetLister = + businessObjectFactory.createDatasetLister(session, dataStoreBaseURL); + datasets = datasetLister.listBySampleIds(sampleIds); + datasets = ScreeningUtils.filterExternalDataByType(datasets, datasetTypeCode); + } + + private void initializeSampleMaps() + { + samplesByIdentifier = new HashMap<SampleIdentifier, Sample>(); + samplesById = new HashMap<Long, Sample>(); + for (Sample sample : samples) + { + samplesByIdentifier.put(createSampleIdentifier(sample), sample); + samplesById.put(sample.getId(), sample); + } + } + + /** + * Filter the list of samples, which were selected by code, to those that exactly match the + * identifiers in the plates + */ + private void filterSamplesByPlateIdentifiers() + { + for (PlateIdentifier plate : plates) + { + Sample sample = samplesByIdentifier.get(createSampleIdentifier(plate)); + // Make sure the sample and plate have the same *identifier* not just code + String plateSpaceCodeOrNull = plate.tryGetSpaceCode(); + Space sampleSpaceOrNull = sample.getSpace(); + String sampleSpaceCodeOrNull = + (null == sampleSpaceOrNull) ? null : sampleSpaceOrNull.getCode(); + + // Remove the sample if they don't match + if (plateSpaceCodeOrNull == null) + { + if (sampleSpaceCodeOrNull != null) + { + removeSample(sample); + } + } else if (false == plateSpaceCodeOrNull.equals(sampleSpaceCodeOrNull)) + { + removeSample(sample); + } + } + } + + private void removeSample(Sample sample) + { + samplesByIdentifier.remove(createSampleIdentifier(sample)); + samplesById.remove(sample.getId()); + samples.remove(sample); + } + + protected PlateIdentifier createPlateIdentifier(ExternalData parentDataset) + { + Sample sample = getSample(parentDataset); + final String plateCode = sample.getCode(); + Space space = sample.getSpace(); + final String spaceCodeOrNull = (space != null) ? space.getCode() : null; + return new PlateIdentifier(plateCode, spaceCodeOrNull); + } + + protected Geometry extractPlateGeometry(ExternalData dataSet) + { + Sample sample = getSample(dataSet); + List<IEntityProperty> properties = sample.getProperties(); + for (IEntityProperty property : properties) + { + PropertyType propertyType = property.getPropertyType(); + if (propertyType.getCode().equals(ScreeningConstants.PLATE_GEOMETRY)) + { + String code = property.getVocabularyTerm().getCode(); + int lastIndexOfUnderscore = code.lastIndexOf('_'); + int lastIndexOfX = code.lastIndexOf('X'); + if (lastIndexOfUnderscore < 0 || lastIndexOfX < 0) + { + throw new UserFailureException("Invalid property " + + ScreeningConstants.PLATE_GEOMETRY + ": " + code); + } + try + { + int width = + Integer.parseInt(code + .substring(lastIndexOfUnderscore + 1, lastIndexOfX)); + int height = Integer.parseInt(code.substring(lastIndexOfX + 1)); + return new Geometry(width, height); + } catch (NumberFormatException ex) + { + throw new UserFailureException("Invalid property " + + ScreeningConstants.PLATE_GEOMETRY + ": " + code); + } + + } + } + throw new UserFailureException("Sample " + sample.getIdentifier() + " has no property " + + ScreeningConstants.PLATE_GEOMETRY); + } + + private Sample getSample(ExternalData dataset) + { + // Sample may be NULL even though the selector does not begin with try + Sample sample = dataset.getSample(); + assert sample != null : "dataset not connected to a sample: " + dataset; + + // The dataset's reference to the sample is not complete, get the one from the map + return samplesById.get(sample.getId()); + } + + private String[] extractSampleCodes() + { + ArrayList<String> sampleCodes = new ArrayList<String>(); + for (PlateIdentifier plate : plates) + { + sampleCodes.add(plate.getPlateCode()); + } + + String[] sampleCodesArray = new String[sampleCodes.size()]; + sampleCodes.toArray(sampleCodesArray); + + return sampleCodesArray; + } + + private List<Long> extractSampleIds() + { + ArrayList<Long> sampleIds = new ArrayList<Long>(); + for (Sample sample : samples) + { + sampleIds.add(sample.getId()); + } + return sampleIds; + } + + protected static SampleIdentifier createSampleIdentifier(PlateIdentifier plate) + { + SampleOwnerIdentifier owner; + String spaceCode = plate.tryGetSpaceCode(); + if (spaceCode != null) + { + SpaceIdentifier space = new SpaceIdentifier(DatabaseInstanceIdentifier.HOME, spaceCode); + owner = new SampleOwnerIdentifier(space); + } else + { + owner = new SampleOwnerIdentifier(DatabaseInstanceIdentifier.createHome()); + } + return SampleIdentifier.createOwnedBy(owner, plate.getPlateCode()); + } + + protected static SampleIdentifier createSampleIdentifier(Sample sample) + { + SampleOwnerIdentifier owner; + Space spaceOrNull = sample.getSpace(); + String spaceCode = (null == spaceOrNull) ? null : spaceOrNull.getCode(); + if (spaceCode != null) + { + SpaceIdentifier space = new SpaceIdentifier(DatabaseInstanceIdentifier.HOME, spaceCode); + owner = new SampleOwnerIdentifier(space); + } else + { + owner = new SampleOwnerIdentifier(DatabaseInstanceIdentifier.createHome()); + } + return SampleIdentifier.createOwnedBy(owner, sample.getCode()); + } +} 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 b52e5304008..f5077638af0 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 @@ -17,13 +17,10 @@ package ch.systemsx.cisd.openbis.plugin.screening.server.logic; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; -import java.util.Set; import ch.systemsx.cisd.common.exceptions.UserFailureException; import ch.systemsx.cisd.openbis.generic.server.business.bo.IExternalDataBO; -import ch.systemsx.cisd.openbis.generic.server.business.bo.ISampleBO; import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister; import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory; import ch.systemsx.cisd.openbis.generic.server.dataaccess.ISampleTypeDAO; @@ -34,25 +31,13 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project; 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; -import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE; -import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE; -import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE; import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE; -import ch.systemsx.cisd.openbis.generic.shared.dto.GroupPE; -import ch.systemsx.cisd.openbis.generic.shared.dto.PropertyTypePE; -import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE; -import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePropertyPE; import ch.systemsx.cisd.openbis.generic.shared.dto.SampleTypePE; import ch.systemsx.cisd.openbis.generic.shared.dto.Session; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleOwnerIdentifier; -import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier; import ch.systemsx.cisd.openbis.generic.shared.translator.SampleTypeTranslator; import ch.systemsx.cisd.openbis.plugin.screening.server.IScreeningBusinessObjectFactory; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.DatasetIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.FeatureVectorDatasetReference; -import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Geometry; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.IDatasetIdentifier; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.ImageDatasetReference; import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.Plate; @@ -72,211 +57,32 @@ public class ScreeningApiImpl private final IDAOFactory daoFactory; + private final String dataStoreBaseURL; + public ScreeningApiImpl(Session session, IScreeningBusinessObjectFactory businessObjectFactory, - IDAOFactory daoFactory) + IDAOFactory daoFactory, String dataStoreBaseURL) { this.session = session; this.businessObjectFactory = businessObjectFactory; this.daoFactory = daoFactory; + this.dataStoreBaseURL = dataStoreBaseURL; } public List<FeatureVectorDatasetReference> listFeatureVectorDatasets( List<? extends PlateIdentifier> plates) { - List<FeatureVectorDatasetReference> result = new ArrayList<FeatureVectorDatasetReference>(); - List<ImageDatasetReference> imageDatasets = listImageDatasets(plates); - ISampleBO sampleBO = businessObjectFactory.createSampleBO(session); - Set<ExperimentPE> visitedExperiments = new HashSet<ExperimentPE>(); - for (PlateIdentifier plate : plates) - { - ExperimentPE experiment = tryGetExperiment(sampleBO, plate); - if (experiment != null && visitedExperiments.contains(experiment) == false) - { - List<ExternalDataPE> datasets = - daoFactory.getExternalDataDAO().listExternalData(experiment); - List<ExternalDataPE> childrenDatasets = filterChildren(imageDatasets, datasets); - List<ExternalDataPE> featureVectorDatasets = - ScreeningUtils.filterDatasetsByType(childrenDatasets, - ScreeningConstants.IMAGE_ANALYSIS_DATASET_TYPE); - result.addAll(asFeatureVectorDatasets(featureVectorDatasets)); - visitedExperiments.add(experiment); - } - } - return result; - } + FeatureVectorDatasetLoader datasetRetriever = + new FeatureVectorDatasetLoader(session, businessObjectFactory, dataStoreBaseURL, + plates); + List<FeatureVectorDatasetReference> result = datasetRetriever.getFeatureVectorDatasets(); - // return those datasets which have exactly one parent, which is contained in the parent set - private static List<ExternalDataPE> filterChildren( - List<? extends IDatasetIdentifier> parentDatasets, List<ExternalDataPE> datasets) - { - Set<String> parentDatasetCodes = createDatasetCodesSet(parentDatasets); - List<ExternalDataPE> children = new ArrayList<ExternalDataPE>(); - for (ExternalDataPE dataset : datasets) - { - Set<DataPE> parents = dataset.getParents(); - if (parents.size() == 1) - { - DataPE parent = parents.iterator().next(); - if (parentDatasetCodes.contains(parent.getCode())) - { - children.add(dataset); - } - } - } - return children; - } - - private static Set<String> createDatasetCodesSet(List<? extends IDatasetIdentifier> datasets) - { - Set<String> result = new HashSet<String>(); - for (IDatasetIdentifier dataset : datasets) - { - result.add(dataset.getDatasetCode()); - } return result; } - private ExperimentPE tryGetExperiment(ISampleBO sampleBO, PlateIdentifier plate) - { - sampleBO.loadBySampleIdentifier(createSampleIdentifier(plate)); - SamplePE sample = sampleBO.getSample(); - return sample.getExperiment(); - } - public List<ImageDatasetReference> listImageDatasets(List<? extends PlateIdentifier> plates) { - List<ExternalDataPE> datasets = loadDatasets(plates, ScreeningConstants.IMAGE_DATASET_TYPE); - return asImageDatasets(datasets); - } - - // NOTE: this method is slow when a number of plates is big - private List<ExternalDataPE> loadDatasets(List<? extends PlateIdentifier> plates, - String datasetTypeCode) - { - ISampleBO sampleBO = businessObjectFactory.createSampleBO(session); - List<ExternalDataPE> datasets = new ArrayList<ExternalDataPE>(); - for (PlateIdentifier plate : plates) - { - List<ExternalDataPE> plateDatasets = loadDatasets(plate, datasetTypeCode, sampleBO); - datasets.addAll(plateDatasets); - } - return datasets; - } - - private List<ExternalDataPE> loadDatasets(PlateIdentifier plate, String datasetTypeCode, - ISampleBO sampleBO) - { - sampleBO.loadBySampleIdentifier(createSampleIdentifier(plate)); - SamplePE sample = sampleBO.getSample(); - List<ExternalDataPE> datasets = daoFactory.getExternalDataDAO().listExternalData(sample); - datasets = ScreeningUtils.filterDatasetsByType(datasets, datasetTypeCode); - return datasets; - } - - private static List<FeatureVectorDatasetReference> asFeatureVectorDatasets( - List<ExternalDataPE> datasets) - { - List<FeatureVectorDatasetReference> result = new ArrayList<FeatureVectorDatasetReference>(); - for (ExternalDataPE externalData : datasets) - { - result.add(asFeatureVectorDataset(externalData)); - } - return result; - } - - private static FeatureVectorDatasetReference asFeatureVectorDataset(ExternalDataPE externalData) - { - DataStorePE dataStore = externalData.getDataStore(); - DataPE parentDataset = externalData.getParents().iterator().next(); - return new FeatureVectorDatasetReference(externalData.getCode(), - dataStore.getDownloadUrl(), createPlateIdentifier(parentDataset), - extractPlateGeometry(parentDataset), externalData.getRegistrationDate(), - asImageDataset(parentDataset)); - } - - private static List<ImageDatasetReference> asImageDatasets(List<ExternalDataPE> datasets) - { - List<ImageDatasetReference> result = new ArrayList<ImageDatasetReference>(); - for (ExternalDataPE externalData : datasets) - { - result.add(asImageDataset(externalData)); - } - return result; - } - - private static ImageDatasetReference asImageDataset(DataPE parentDataset) - { - DataStorePE dataStore = parentDataset.getDataStore(); - return new ImageDatasetReference(parentDataset.getCode(), dataStore.getDownloadUrl(), - createPlateIdentifier(parentDataset), extractPlateGeometry(parentDataset), - parentDataset.getRegistrationDate()); - } - - private static PlateIdentifier createPlateIdentifier(DataPE parentDataset) - { - SamplePE sample = getSample(parentDataset); - final String plateCode = sample.getCode(); - GroupPE group = sample.getGroup(); - final String spaceCodeOrNull = (group != null) ? group.getCode() : null; - return new PlateIdentifier(plateCode, spaceCodeOrNull); - } - - private static SamplePE getSample(DataPE dataset) - { - SamplePE sample = dataset.tryGetSample(); - assert sample != null : "dataset not connected to a sample: " + dataset; - return sample; - } - - private static Geometry extractPlateGeometry(DataPE dataSet) - { - SamplePE sample = getSample(dataSet); - Set<SamplePropertyPE> properties = sample.getProperties(); - for (SamplePropertyPE property : properties) - { - PropertyTypePE propertyType = property.getEntityTypePropertyType().getPropertyType(); - if (propertyType.getCode().equals(ScreeningConstants.PLATE_GEOMETRY)) - { - String code = property.getVocabularyTerm().getCode(); - int lastIndexOfUnderscore = code.lastIndexOf('_'); - int lastIndexOfX = code.lastIndexOf('X'); - if (lastIndexOfUnderscore < 0 || lastIndexOfX < 0) - { - throw new UserFailureException("Invalid property " - + ScreeningConstants.PLATE_GEOMETRY + ": " + code); - } - try - { - int width = - Integer.parseInt(code - .substring(lastIndexOfUnderscore + 1, lastIndexOfX)); - int height = Integer.parseInt(code.substring(lastIndexOfX + 1)); - return new Geometry(width, height); - } catch (NumberFormatException ex) - { - throw new UserFailureException("Invalid property " - + ScreeningConstants.PLATE_GEOMETRY + ": " + code); - } - - } - } - throw new UserFailureException("Sample " + sample.getIdentifier() + " has no property " - + ScreeningConstants.PLATE_GEOMETRY); - } - - private static SampleIdentifier createSampleIdentifier(PlateIdentifier plate) - { - SampleOwnerIdentifier owner; - String spaceCode = plate.tryGetSpaceCode(); - if (spaceCode != null) - { - SpaceIdentifier space = new SpaceIdentifier(DatabaseInstanceIdentifier.HOME, spaceCode); - owner = new SampleOwnerIdentifier(space); - } else - { - owner = new SampleOwnerIdentifier(DatabaseInstanceIdentifier.createHome()); - } - return SampleIdentifier.createOwnedBy(owner, plate.getPlateCode()); + return new ImageDatasetLoader(session, businessObjectFactory, dataStoreBaseURL, plates) + .getImageDatasets(); } public List<Plate> listPlates() diff --git a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningUtils.java b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningUtils.java index 9b3725c9f8d..62ac9b54693 100644 --- a/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningUtils.java +++ b/screening/source/java/ch/systemsx/cisd/openbis/plugin/screening/server/logic/ScreeningUtils.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import ch.systemsx.cisd.bds.hcs.Location; +import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData; import ch.systemsx.cisd.openbis.generic.shared.dto.DataStorePE; import ch.systemsx.cisd.openbis.generic.shared.dto.ExternalDataPE; import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.DatasetReference; @@ -81,4 +82,23 @@ public class ScreeningUtils return dataset.getDataSetType().getCode().equals(datasetType); } + public static List<ExternalData> filterExternalDataByType(List<ExternalData> datasets, + String datasetTypeCode) + { + List<ExternalData> chosenDatasets = new ArrayList<ExternalData>(); + for (ExternalData dataset : datasets) + { + if (isTypeEqual(dataset, datasetTypeCode)) + { + chosenDatasets.add(dataset); + } + } + return chosenDatasets; + } + + private static boolean isTypeEqual(ExternalData dataset, String datasetType) + { + return dataset.getDataSetType().getCode().equals(datasetType); + } + } 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 0a648d3d203..43a2a1ffd2f 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 @@ -44,23 +44,23 @@ import ch.systemsx.cisd.openbis.plugin.screening.shared.api.v1.dto.PlateIdentifi import ch.systemsx.cisd.openbis.plugin.screening.shared.basic.dto.ScreeningConstants; /** - * - * * @author Franz-Josef Elmer */ public class ScreeningApiImplTest extends AbstractServerTestCase { private static final String SERVER_URL = "server-url"; + private IScreeningBusinessObjectFactory screeningBOFactory; + private ScreeningApiImpl screeningApi; @BeforeMethod public void beforeMethod() { screeningBOFactory = context.mock(IScreeningBusinessObjectFactory.class); - screeningApi = new ScreeningApiImpl(SESSION, screeningBOFactory, daoFactory); + screeningApi = new ScreeningApiImpl(SESSION, screeningBOFactory, daoFactory, ""); } - + @Test public void testListImageDatasets() { @@ -82,8 +82,8 @@ public class ScreeningApiImplTest extends AbstractServerTestCase } }); - List<ImageDatasetReference> dataSets = screeningApi.listImageDatasets(Arrays.asList(pi1)); - + List<ImageDatasetReference> dataSets = screeningApi.listImageDatasets(Arrays.asList(pi1)); + assertEquals("1", dataSets.get(0).getDatasetCode()); assertEquals(new Geometry(16, 24), dataSets.get(0).getPlateGeometry()); assertEquals(new Date(100), dataSets.get(0).getRegistrationDate()); @@ -92,7 +92,7 @@ public class ScreeningApiImplTest extends AbstractServerTestCase assertEquals(1, dataSets.size()); context.assertIsSatisfied(); } - + @Test public void testListImageDatasetsWithMissingPlateGeometry() { @@ -124,7 +124,7 @@ public class ScreeningApiImplTest extends AbstractServerTestCase } context.assertIsSatisfied(); } - + @Test public void testListImageDatasetsWithPlateGeometryWithMissingUnderscore() { @@ -138,40 +138,40 @@ public class ScreeningApiImplTest extends AbstractServerTestCase assertListImageDatasetsFailsFor("abc_2.4"); context.assertIsSatisfied(); } - + @Test public void testListImageDatasetsWithPlateGeometryWithWidthNotANumber() { assertListImageDatasetsFailsFor("abc_aX4"); context.assertIsSatisfied(); } - + @Test public void testListImageDatasetsWithPlateGeometryWithHeightNotANumber() { assertListImageDatasetsFailsFor("abc_2Xb"); context.assertIsSatisfied(); } - + private void assertListImageDatasetsFailsFor(final String plateGeometry) { final PlateIdentifier pi1 = new PlateIdentifier("p1", null); context.checking(new Expectations() - { { - one(screeningBOFactory).createSampleBO(SESSION); - will(returnValue(sampleBO)); - - one(sampleBO).loadBySampleIdentifier(asSampleIdentifier(pi1)); - one(sampleBO).getSample(); - SamplePE p1 = plate(pi1, plateGeometry); - will(returnValue(p1)); - - one(externalDataDAO).listExternalData(p1); - will(returnValue(Arrays.asList(imageDataSet(p1, "1")))); - } - }); - + { + one(screeningBOFactory).createSampleBO(SESSION); + will(returnValue(sampleBO)); + + one(sampleBO).loadBySampleIdentifier(asSampleIdentifier(pi1)); + one(sampleBO).getSample(); + SamplePE p1 = plate(pi1, plateGeometry); + will(returnValue(p1)); + + one(externalDataDAO).listExternalData(p1); + will(returnValue(Arrays.asList(imageDataSet(p1, "1")))); + } + }); + try { screeningApi.listImageDatasets(Arrays.asList(pi1)); @@ -182,7 +182,7 @@ public class ScreeningApiImplTest extends AbstractServerTestCase + plateGeometry.toUpperCase(), ex.getMessage()); } } - + private SampleIdentifier asSampleIdentifier(PlateIdentifier plateIdentifier) { String spaceCode = plateIdentifier.tryGetSpaceCode(); @@ -194,7 +194,7 @@ public class ScreeningApiImplTest extends AbstractServerTestCase return new SampleIdentifier(new SpaceIdentifier(DatabaseInstanceIdentifier.createHome(), spaceCode), plateIdentifier.getPlateCode()); } - + private SamplePE plate(PlateIdentifier plateIdentifier, String plateGeometryOrNull) { SamplePE sample = new SamplePE(); @@ -228,7 +228,7 @@ public class ScreeningApiImplTest extends AbstractServerTestCase dataSet.setDataSetType(dataSetType(ScreeningConstants.IMAGE_ANALYSIS_DATASET_TYPE)); return dataSet; } - + private ExternalDataPE createDataSet(SamplePE sample, String code) { ExternalDataPE dataSet = new ExternalDataPE(); @@ -240,7 +240,7 @@ public class ScreeningApiImplTest extends AbstractServerTestCase dataSet.setRegistrationDate(new Date(Long.parseLong(code) * 100)); return dataSet; } - + private DataSetTypePE dataSetType(String code) { DataSetTypePE type = new DataSetTypePE(); -- GitLab