From 49283c319fdd78e86f28b28c20298c544434cf6d Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Mon, 27 Jun 2022 15:58:59 +0200 Subject: [PATCH] Add methods to create a screen and refactor code to import images to screens --- .../omero/repository/DatasetWrapper.java | 82 +----------- .../GenericRepositoryObjectWrapper.java | 120 ++++++++++++++++++ .../igred/omero/repository/ScreenWrapper.java | 95 ++++++++++++++ .../fr/igred/omero/repository/ScreenTest.java | 87 +++++++++++++ 4 files changed, 305 insertions(+), 79 deletions(-) diff --git a/src/main/java/fr/igred/omero/repository/DatasetWrapper.java b/src/main/java/fr/igred/omero/repository/DatasetWrapper.java index c67d3ca9..0f7da74f 100644 --- a/src/main/java/fr/igred/omero/repository/DatasetWrapper.java +++ b/src/main/java/fr/igred/omero/repository/DatasetWrapper.java @@ -25,18 +25,7 @@ import fr.igred.omero.exception.OMEROServerError; import fr.igred.omero.exception.ServiceException; import fr.igred.omero.roi.ROIWrapper; -import loci.formats.in.DefaultMetadataOptions; -import loci.formats.in.MetadataLevel; -import ome.formats.OMEROMetadataStoreClient; -import ome.formats.importer.ImportCandidates; -import ome.formats.importer.ImportConfig; -import ome.formats.importer.ImportContainer; -import ome.formats.importer.ImportLibrary; -import ome.formats.importer.OMEROWrapper; -import ome.formats.importer.cli.ErrorHandler; -import ome.formats.importer.cli.LoggingImportMonitor; import omero.RLong; -import omero.ServerError; import omero.gateway.exception.DSAccessException; import omero.gateway.exception.DSOutOfServiceException; import omero.gateway.model.DatasetData; @@ -45,7 +34,6 @@ import omero.model.DatasetImageLink; import omero.model.DatasetImageLinkI; import omero.model.IObject; -import omero.model.Pixels; import java.io.IOException; import java.util.ArrayList; @@ -55,8 +43,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.stream.Collectors; import static fr.igred.omero.exception.ExceptionHandler.handleServiceOrAccess; @@ -445,31 +431,7 @@ public void removeImage(Client client, ImageWrapper image) */ public boolean importImages(Client client, String... paths) throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException { - boolean success; - - ImportConfig config = new ImportConfig(); - config.target.set("Dataset:" + data.getId()); - config.username.set(client.getUser().getUserName()); - config.email.set(client.getUser().getEmail()); - - OMEROMetadataStoreClient store = client.getImportStore(); - try (OMEROWrapper reader = new OMEROWrapper(config)) { - store.logVersionInfo(config.getIniVersionNumber()); - reader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL)); - - ImportLibrary library = new ImportLibrary(store, reader); - library.addObserver(new LoggingImportMonitor()); - - ErrorHandler handler = new ErrorHandler(config); - - ImportCandidates candidates = new ImportCandidates(reader, paths, handler); - success = library.importCandidates(config, candidates); - } catch (ServerError se) { - throw new OMEROServerError(se); - } finally { - store.logout(); - } - + boolean success = importImages(client, data, paths); refresh(client); return success; } @@ -490,47 +452,9 @@ public boolean importImages(Client client, String... paths) */ public List importImage(Client client, String path) throws ServiceException, AccessException, OMEROServerError, ExecutionException { - ImportConfig config = new ImportConfig(); - config.target.set("Dataset:" + data.getId()); - config.username.set(client.getUser().getUserName()); - config.email.set(client.getUser().getEmail()); - - Collection pixels = new ArrayList<>(1); - - OMEROMetadataStoreClient store = client.getImportStore(); - try (OMEROWrapper reader = new OMEROWrapper(config)) { - store.logVersionInfo(config.getIniVersionNumber()); - reader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL)); - - ImportLibrary library = new ImportLibrary(store, reader); - library.addObserver(new LoggingImportMonitor()); - - ErrorHandler handler = new ErrorHandler(config); - - ImportCandidates candidates = new ImportCandidates(reader, new String[]{path}, handler); - - ExecutorService uploadThreadPool = Executors.newFixedThreadPool(config.parallelUpload.get()); - - List containers = candidates.getContainers(); - if (containers != null) { - for (int i = 0; i < containers.size(); i++) { - ImportContainer container = containers.get(i); - container.setTarget(data.asDataset()); - List imported = library.importImage(container, uploadThreadPool, i); - pixels.addAll(imported); - } - } - uploadThreadPool.shutdown(); - } catch (Throwable e) { - throw new OMEROServerError(e); - } finally { - store.logout(); - } + List ids = importImage(client, data, path); refresh(client); - - List ids = new ArrayList<>(pixels.size()); - pixels.forEach(pix -> ids.add(pix.getImage().getId().getValue())); - return ids.stream().distinct().collect(Collectors.toList()); + return ids; } diff --git a/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java b/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java index 18e432f9..7385b45b 100644 --- a/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java +++ b/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java @@ -17,6 +17,7 @@ import fr.igred.omero.Client; +import fr.igred.omero.GatewayWrapper; import fr.igred.omero.GenericObjectWrapper; import fr.igred.omero.annotations.FileAnnotationWrapper; import fr.igred.omero.annotations.GenericAnnotationWrapper; @@ -26,6 +27,17 @@ import fr.igred.omero.exception.AccessException; import fr.igred.omero.exception.OMEROServerError; import fr.igred.omero.exception.ServiceException; +import loci.formats.in.DefaultMetadataOptions; +import loci.formats.in.MetadataLevel; +import ome.formats.OMEROMetadataStoreClient; +import ome.formats.importer.ImportCandidates; +import ome.formats.importer.ImportConfig; +import ome.formats.importer.ImportContainer; +import ome.formats.importer.ImportLibrary; +import ome.formats.importer.OMEROWrapper; +import ome.formats.importer.cli.ErrorHandler; +import ome.formats.importer.cli.LoggingImportMonitor; +import omero.ServerError; import omero.constants.metadata.NSCLIENTMAPANNOTATION; import omero.gateway.exception.DSAccessException; import omero.gateway.exception.DSOutOfServiceException; @@ -35,11 +47,14 @@ import omero.gateway.model.MapAnnotationData; import omero.gateway.model.TableData; import omero.gateway.model.TagAnnotationData; +import omero.gateway.util.PojoMapper; import omero.model.IObject; import omero.model.NamedValue; +import omero.model.Pixels; import omero.model.TagAnnotationI; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -49,6 +64,8 @@ import java.util.NoSuchElementException; import java.util.Objects; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.stream.Collectors; import static fr.igred.omero.exception.ExceptionHandler.handleServiceOrAccess; @@ -680,6 +697,109 @@ public void copyAnnotationLinks(Client client, GenericRepositoryObjectWrapper } + /** + * Imports all images candidates in the paths to the target in OMERO. + * + * @param client The client handling the connection. + * @param target The import target. + * @param paths Paths to the image files on the computer. + * + * @return If the import did not exit because of an error. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws OMEROServerError Server error. + * @throws IOException Cannot read file. + */ + protected static boolean importImages(GatewayWrapper client, DataObject target, String... paths) + throws ServiceException, OMEROServerError, IOException { + boolean success; + + ImportConfig config = new ImportConfig(); + String type = PojoMapper.getGraphType(target.getClass()); + config.target.set(type + ":" + target.getId()); + config.username.set(client.getUser().getUserName()); + config.email.set(client.getUser().getEmail()); + + OMEROMetadataStoreClient store = client.getImportStore(); + try (OMEROWrapper reader = new OMEROWrapper(config)) { + store.logVersionInfo(config.getIniVersionNumber()); + reader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL)); + + ImportLibrary library = new ImportLibrary(store, reader); + library.addObserver(new LoggingImportMonitor()); + + ErrorHandler handler = new ErrorHandler(config); + + ImportCandidates candidates = new ImportCandidates(reader, paths, handler); + success = library.importCandidates(config, candidates); + } catch (ServerError se) { + throw new OMEROServerError(se); + } finally { + store.logout(); + } + + return success; + } + + + /** + * Imports one image file to the target in OMERO. + * + * @param client The client handling the connection. + * @param target The import target. + * @param path Path to the image file on the computer. + * + * @return The list of IDs of the newly imported images. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws OMEROServerError Server error. + */ + protected static List importImage(GatewayWrapper client, DataObject target, String path) + throws ServiceException, OMEROServerError { + ImportConfig config = new ImportConfig(); + String type = PojoMapper.getGraphType(target.getClass()); + config.target.set(type + ":" + target.getId()); + config.username.set(client.getUser().getUserName()); + config.email.set(client.getUser().getEmail()); + + Collection pixels = new ArrayList<>(1); + + OMEROMetadataStoreClient store = client.getImportStore(); + try (OMEROWrapper reader = new OMEROWrapper(config)) { + store.logVersionInfo(config.getIniVersionNumber()); + reader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL)); + + ImportLibrary library = new ImportLibrary(store, reader); + library.addObserver(new LoggingImportMonitor()); + + ErrorHandler handler = new ErrorHandler(config); + + ImportCandidates candidates = new ImportCandidates(reader, new String[]{path}, handler); + + ExecutorService uploadThreadPool = Executors.newFixedThreadPool(config.parallelUpload.get()); + + List containers = candidates.getContainers(); + if (containers != null) { + for (int i = 0; i < containers.size(); i++) { + ImportContainer container = containers.get(i); + container.setTarget(target.asIObject()); + List imported = library.importImage(container, uploadThreadPool, i); + pixels.addAll(imported); + } + } + uploadThreadPool.shutdown(); + } catch (Throwable e) { + throw new OMEROServerError(e); + } finally { + store.logout(); + } + + List ids = new ArrayList<>(pixels.size()); + pixels.forEach(pix -> ids.add(pix.getImage().getId().getValue())); + return ids.stream().distinct().collect(Collectors.toList()); + } + + /** * Policy to specify how to handle objects when they are replaced. */ diff --git a/src/main/java/fr/igred/omero/repository/ScreenWrapper.java b/src/main/java/fr/igred/omero/repository/ScreenWrapper.java index fd1cf601..f42f06af 100644 --- a/src/main/java/fr/igred/omero/repository/ScreenWrapper.java +++ b/src/main/java/fr/igred/omero/repository/ScreenWrapper.java @@ -17,9 +17,21 @@ package fr.igred.omero.repository; +import fr.igred.omero.Client; +import fr.igred.omero.GatewayWrapper; +import fr.igred.omero.exception.AccessException; +import fr.igred.omero.exception.OMEROServerError; +import fr.igred.omero.exception.ServiceException; +import omero.gateway.exception.DSAccessException; +import omero.gateway.exception.DSOutOfServiceException; import omero.gateway.model.ScreenData; +import java.io.IOException; +import java.util.Collections; import java.util.List; +import java.util.concurrent.ExecutionException; + +import static fr.igred.omero.exception.ExceptionHandler.handleServiceOrAccess; public class ScreenWrapper extends GenericRepositoryObjectWrapper { @@ -27,6 +39,26 @@ public class ScreenWrapper extends GenericRepositoryObjectWrapper { public static final String ANNOTATION_LINK = "ScreenAnnotationLink"; + /** + * Constructor of the ProjectWrapper class. Creates a new project and saves it to OMERO. + * + * @param client The client handling the connection. + * @param name Project name. + * @param description Project description. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + */ + public ScreenWrapper(Client client, String name, String description) + throws ServiceException, AccessException, ExecutionException { + super(new ScreenData()); + data.setName(name); + data.setDescription(description); + super.saveAndUpdate(client); + } + + /** * Constructor of the class ScreenWrapper. * @@ -203,4 +235,67 @@ public void setReagentSetIdentifier(String value) { data.setReagentSetIdentifier(value); } + + /** + * Refreshes the wrapped screen. + * + * @param client The client handling the connection. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + */ + public void refresh(GatewayWrapper client) throws ServiceException, AccessException, ExecutionException { + try { + data = client.getBrowseFacility() + .getScreens(client.getCtx(), Collections.singletonList(this.getId())) + .iterator().next(); + } catch (DSOutOfServiceException | DSAccessException e) { + handleServiceOrAccess(e, "Cannot refresh " + this); + } + } + + + /** + * Imports all images candidates in the paths to the screen in OMERO. + * + * @param client The client handling the connection. + * @param paths Paths to the image files on the computer. + * + * @return If the import did not exit because of an error. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws OMEROServerError Server error. + * @throws IOException Cannot read file. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + */ + public boolean importImages(GatewayWrapper client, String... paths) + throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException { + boolean success = importImages(client, data, paths); + refresh(client); + return success; + } + + + /** + * Imports one image file to the screen in OMERO. + * + * @param client The client handling the connection. + * @param path Path to the image file on the computer. + * + * @return The list of IDs of the newly imported images. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws OMEROServerError Server error. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + */ + public List importImage(GatewayWrapper client, String path) + throws ServiceException, AccessException, OMEROServerError, ExecutionException { + List ids = importImage(client, data, path); + refresh(client); + return ids; + } + } diff --git a/src/test/java/fr/igred/omero/repository/ScreenTest.java b/src/test/java/fr/igred/omero/repository/ScreenTest.java index 4b44df41..29277c95 100644 --- a/src/test/java/fr/igred/omero/repository/ScreenTest.java +++ b/src/test/java/fr/igred/omero/repository/ScreenTest.java @@ -20,9 +20,12 @@ import fr.igred.omero.annotations.TagAnnotationWrapper; import org.junit.Test; +import java.io.File; import java.util.List; +import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class ScreenTest extends UserTest { @@ -135,4 +138,88 @@ public void testSetReagentSetIdentifier() throws Exception { assertEquals(identifier, client.getScreen(SCREEN1.id).getReagentSetIdentifier()); } + + @Test + public void testImportImages() throws Exception { + + String filename1 = "default-screen&screens=1&plates=1&plateAcqs=1&plateRows=3&plateCols=3&fields=4.fake"; + String filename2 = "default-screen&screens=1&plates=1&plateAcqs=1&plateRows=2&plateCols=2&fields=2.fake"; + + File f1 = createFile(filename1); + File f2 = createFile(filename2); + + ScreenWrapper screen = new ScreenWrapper(client, "Import", "test-import"); + + boolean imported = screen.importImages(client, f1.getAbsolutePath(), f2.getAbsolutePath()); + + removeFile(f1); + removeFile(f2); + + List plates = screen.getPlates(); + assertEquals(2, plates.size()); + List wells = plates.get(0).getWells(client); + wells.addAll(plates.get(1).getWells(client)); + assertEquals(13, wells.size()); + List samples = wells.stream() + .map(WellWrapper::getWellSamples) + .flatMap(List::stream) + .collect(Collectors.toList()); + assertEquals(44, samples.size()); + List images = samples.stream() + .map(WellSampleWrapper::getImage) + .collect(Collectors.toList()); + + client.delete(images); + client.delete(samples); + client.delete(wells); + client.delete(plates); + + screen.refresh(client); + assertTrue(screen.getPlates().isEmpty()); + + client.delete(screen); + assertTrue(imported); + } + + + @Test + public void testImportImage() throws Exception { + + String filename = "default-screen&screens=1&plates=1&plateAcqs=1&plateRows=2&plateCols=2&fields=2.fake"; + + File f = createFile(filename); + + ScreenWrapper screen = new ScreenWrapper(client, "Import", "test-import"); + + List ids = screen.importImage(client, f.getAbsolutePath()); + + removeFile(f); + + List plates = screen.getPlates(); + assertEquals(1, plates.size()); + List wells = plates.get(0).getWells(client); + assertEquals(4, wells.size()); + List samples = wells.stream() + .map(WellWrapper::getWellSamples) + .flatMap(List::stream) + .collect(Collectors.toList()); + assertEquals(8, samples.size()); + List images = samples.stream() + .map(WellSampleWrapper::getImage) + .collect(Collectors.toList()); + + assertEquals(images.size(), ids.size()); + client.delete(images); + client.delete(samples); + client.delete(wells); + client.delete(plates); + + screen.refresh(client); + List endPlates = screen.getPlates(); + + client.delete(screen); + + assertTrue(endPlates.isEmpty()); + } + }