From 03467d21a441c9fa0e89003b7833d47e02eee8af Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Thu, 8 Jun 2023 15:27:05 +0200 Subject: [PATCH 1/3] Bump version --- pom.xml | 4 ++-- src/main/java/fr/igred/omero/GatewayWrapper.java | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 872b2a06..317a106a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,12 +4,12 @@ pom-scijava org.scijava - 34.1.0 + 35.1.1 fr.igred simple-omero-client - 5.12.3 + 5.13.0 jar Simple OMERO Client diff --git a/src/main/java/fr/igred/omero/GatewayWrapper.java b/src/main/java/fr/igred/omero/GatewayWrapper.java index 13cc57e7..e88bcfe6 100644 --- a/src/main/java/fr/igred/omero/GatewayWrapper.java +++ b/src/main/java/fr/igred/omero/GatewayWrapper.java @@ -26,7 +26,6 @@ import ome.formats.OMEROMetadataStoreClient; import omero.api.IQueryPrx; import omero.gateway.Gateway; -import omero.gateway.JoinSessionCredentials; import omero.gateway.LoginCredentials; import omero.gateway.SecurityContext; import omero.gateway.exception.DSOutOfServiceException; @@ -163,7 +162,7 @@ public boolean isConnected() { */ public void connect(String hostname, int port, String sessionId) throws ServiceException { - connect(new JoinSessionCredentials(sessionId, hostname, port)); + connect(new LoginCredentials(sessionId, sessionId, hostname, port)); } From a7b2f0ad310c750e960e4a5289923e1f78050c82 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Mon, 12 Jun 2023 16:38:56 +0200 Subject: [PATCH 2/3] Make import thread-safe to fix #60 --- .../java/fr/igred/omero/GatewayWrapper.java | 56 ++++++++++++++++++- .../GenericRepositoryObjectWrapper.java | 4 +- src/test/java/fr/igred/omero/SudoTest.java | 2 + 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/igred/omero/GatewayWrapper.java b/src/main/java/fr/igred/omero/GatewayWrapper.java index e88bcfe6..e30c7238 100644 --- a/src/main/java/fr/igred/omero/GatewayWrapper.java +++ b/src/main/java/fr/igred/omero/GatewayWrapper.java @@ -42,6 +42,9 @@ import java.util.List; import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** @@ -51,6 +54,12 @@ */ public abstract class GatewayWrapper { + /** Number of requested import stores */ + private final AtomicInteger storeUses = new AtomicInteger(0); + + /** Import store lock */ + private final Lock storeLock = new ReentrantLock(true); + /** Gateway linking the code to OMERO, only linked to one group. */ private Gateway gateway; @@ -86,6 +95,35 @@ public Gateway getGateway() { } + /** + * Retrieves the shared import store in a thread-safe way. + * + * @throws DSOutOfServiceException If the connection is broken, or not logged in. + */ + private OMEROMetadataStoreClient getImportStoreLocked() throws DSOutOfServiceException { + storeLock.lock(); + try { + return gateway.getImportStore(ctx); + } finally { + storeLock.unlock(); + } + } + + + /** + * Closes the import store in a thread-safe manner. + */ + private void closeImportStoreLocked() { + if (storeLock.tryLock()) { + try { + gateway.closeImport(ctx, null); + } finally { + storeLock.unlock(); + } + } + } + + /** * Returns the current user. * @@ -232,6 +270,8 @@ public void connect(LoginCredentials cred) throws ServiceException { public void disconnect() { if (isConnected()) { boolean sudo = ctx.isSudo(); + storeUses.set(0); + closeImport(); user = new ExperimenterWrapper(new ExperimenterData()); ctx = new SecurityContext(-1); ctx.setExperimenter(user.asDataObject()); @@ -347,18 +387,30 @@ public AdminFacility getAdminFacility() throws ExecutionException { /** * Creates or recycles the import store. * - * @return config. + * @return See above. * * @throws ServiceException Cannot connect to OMERO. */ public OMEROMetadataStoreClient getImportStore() throws ServiceException { - return ExceptionHandler.of(gateway, g -> g.getImportStore(ctx)) + storeUses.incrementAndGet(); + return ExceptionHandler.of(this, GatewayWrapper::getImportStoreLocked) .rethrow(DSOutOfServiceException.class, ServiceException::new, "Could not retrieve import store") .get(); } + /** + * Closes the import store. + */ + public void closeImport() { + int remainingStores = storeUses.decrementAndGet(); + if (remainingStores <= 0) { + closeImportStoreLocked(); + } + } + + /** * Finds objects on OMERO through a database query. * diff --git a/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java b/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java index 538f597e..b19b379c 100644 --- a/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java +++ b/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java @@ -107,7 +107,7 @@ protected static boolean importImages(GatewayWrapper client, DataObject target, ImportCandidates candidates = new ImportCandidates(reader, paths, handler); success = library.importCandidates(config, candidates); } finally { - store.logout(); + client.closeImport(); } return success; @@ -163,7 +163,7 @@ protected static List importImage(GatewayWrapper client, DataObject target } catch (Throwable e) { throw new OMEROServerError(e); } finally { - store.logout(); + client.closeImport(); } List ids = new ArrayList<>(pixels.size()); diff --git a/src/test/java/fr/igred/omero/SudoTest.java b/src/test/java/fr/igred/omero/SudoTest.java index d8563eae..5a3ff273 100644 --- a/src/test/java/fr/igred/omero/SudoTest.java +++ b/src/test/java/fr/igred/omero/SudoTest.java @@ -109,6 +109,8 @@ void sudoImport() throws Exception { List images = dataset.getImages(client3); assertEquals(1, images.size()); + assertEquals(client3.getId(), images.get(0).getOwner().getId()); + assertEquals(6L, images.get(0).getGroupId()); client4.delete(images.get(0)); client4.delete(dataset); From 07eae6c87ca49c116b0b731c1c8deda10bd6e517 Mon Sep 17 00:00:00 2001 From: Pierre Pouchin Date: Fri, 9 Jun 2023 12:21:13 +0200 Subject: [PATCH 3/3] Add method to import images using multiple threads --- .../omero/repository/DatasetWrapper.java | 23 ++++++++++++++++++- .../GenericRepositoryObjectWrapper.java | 11 +++++---- .../igred/omero/repository/ScreenWrapper.java | 23 ++++++++++++++++++- .../omero/repository/ImageImportTest.java | 3 ++- 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/igred/omero/repository/DatasetWrapper.java b/src/main/java/fr/igred/omero/repository/DatasetWrapper.java index 3375ece0..54988ab8 100644 --- a/src/main/java/fr/igred/omero/repository/DatasetWrapper.java +++ b/src/main/java/fr/igred/omero/repository/DatasetWrapper.java @@ -463,7 +463,28 @@ public void removeImage(Client client, ImageWrapper image) */ public boolean importImages(Client client, String... paths) throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException { - boolean success = importImages(client, data, paths); + return importImages(client, 1, paths); + } + + + /** + * Imports all images candidates in the paths to the dataset in OMERO. + * + * @param client The client handling the connection. + * @param threads The number of threads (same value used for filesets and uploads). + * @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(Client client, int threads, String... paths) + throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException { + boolean success = importImages(client, data, threads, paths); refresh(client); return success; } diff --git a/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java b/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java index b19b379c..05a29385 100644 --- a/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java +++ b/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java @@ -70,9 +70,10 @@ protected GenericRepositoryObjectWrapper(T o) { /** * 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. + * @param client The client handling the connection. + * @param target The import target. + * @param threads The number of threads (same value used for filesets and uploads). + * @param paths Paths to the image files on the computer. * * @return If the import did not exit because of an error. * @@ -80,7 +81,7 @@ protected GenericRepositoryObjectWrapper(T o) { * @throws OMEROServerError Server error. * @throws IOException Cannot read file. */ - protected static boolean importImages(GatewayWrapper client, DataObject target, String... paths) + protected static boolean importImages(GatewayWrapper client, DataObject target, int threads, String... paths) throws ServiceException, OMEROServerError, IOException { boolean success; @@ -89,6 +90,8 @@ protected static boolean importImages(GatewayWrapper client, DataObject target, config.target.set(type + ":" + target.getId()); config.username.set(client.getUser().getUserName()); config.email.set(client.getUser().getEmail()); + config.parallelFileset.set(threads); + config.parallelUpload.set(threads); OMEROMetadataStoreClient store = client.getImportStore(); try (OMEROWrapper reader = new OMEROWrapper(config)) { diff --git a/src/main/java/fr/igred/omero/repository/ScreenWrapper.java b/src/main/java/fr/igred/omero/repository/ScreenWrapper.java index f7c2b97a..3c22036d 100644 --- a/src/main/java/fr/igred/omero/repository/ScreenWrapper.java +++ b/src/main/java/fr/igred/omero/repository/ScreenWrapper.java @@ -351,7 +351,28 @@ public void refresh(GatewayWrapper client) throws ServiceException, AccessExcept */ public boolean importImages(GatewayWrapper client, String... paths) throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException { - boolean success = importImages(client, data, paths); + return this.importImages(client, 1, paths); + } + + + /** + * Imports all images candidates in the paths to the screen in OMERO. + * + * @param client The client handling the connection. + * @param threads The number of threads (same value used for filesets and uploads). + * @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, int threads, String... paths) + throws ServiceException, OMEROServerError, AccessException, IOException, ExecutionException { + boolean success = importImages(client, data, threads, paths); refresh(client); return success; } diff --git a/src/test/java/fr/igred/omero/repository/ImageImportTest.java b/src/test/java/fr/igred/omero/repository/ImageImportTest.java index 58210f1b..d6aab45f 100644 --- a/src/test/java/fr/igred/omero/repository/ImageImportTest.java +++ b/src/test/java/fr/igred/omero/repository/ImageImportTest.java @@ -49,7 +49,8 @@ void testImportImage() throws Exception { DatasetWrapper dataset = client.getDataset(DATASET2.id); - boolean imported = dataset.importImages(client, f1.getAbsolutePath(), f2.getAbsolutePath()); + boolean imported = dataset.importImages(client, 2, f1.getAbsolutePath(), f2.getAbsolutePath()); + client.closeImport(); removeFile(f1); removeFile(f2);