diff --git a/src/main/java/fr/igred/omero/Client.java b/src/main/java/fr/igred/omero/Client.java index 1492fd86..779e1fc3 100644 --- a/src/main/java/fr/igred/omero/Client.java +++ b/src/main/java/fr/igred/omero/Client.java @@ -62,6 +62,7 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; +import static fr.igred.omero.GenericObjectWrapper.distinct; import static fr.igred.omero.GenericObjectWrapper.wrap; import static fr.igred.omero.exception.ExceptionHandler.handleServiceOrAccess; import static fr.igred.omero.exception.ExceptionHandler.handleServiceOrServer; @@ -339,7 +340,7 @@ public List getImages() throws ServiceException, AccessException, /** - * Gets all images with a certain from OMERO. + * Gets all images with a certain name from OMERO. * * @param name Name searched. * @@ -376,15 +377,19 @@ public List getImages(String name) throws ServiceException, Access */ public List getImages(String projectName, String datasetName, String imageName) throws ServiceException, AccessException, ExecutionException { - List images = new ArrayList<>(); List projects = getProjects(projectName); + + Collection> lists = new ArrayList<>(projects.size()); for (ProjectWrapper project : projects) { - List datasets = project.getDatasets(datasetName); - for (DatasetWrapper dataset : datasets) { - images.addAll(dataset.getImages(this, imageName)); - } + lists.add(project.getImages(this, datasetName, imageName)); } - return images; + + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); + + return distinct(images); } @@ -457,7 +462,7 @@ public List getImagesTagged(Long tagId) public List getImagesKey(String key) throws ServiceException, AccessException, ExecutionException { List images = getImages(); - List selected = new ArrayList<>(); + List selected = new ArrayList<>(images.size()); for (ImageWrapper image : images) { Map pairsKeyValue = image.getKeyValuePairs(this); if (pairsKeyValue.get(key) != null) { @@ -484,7 +489,7 @@ public List getImagesKey(String key) public List getImagesPairKeyValue(String key, String value) throws ServiceException, AccessException, ExecutionException { List images = getImages(); - List selected = new ArrayList<>(); + List selected = new ArrayList<>(images.size()); for (ImageWrapper image : images) { Map pairsKeyValue = image.getKeyValuePairs(this); if (pairsKeyValue.get(key) != null && pairsKeyValue.get(key).equals(value)) { @@ -756,6 +761,30 @@ public TagAnnotationWrapper getTag(Long id) throws OMEROServerError, ServiceExce } + /** + * Deletes multiple objects from OMERO. + * + * @param objects The OMERO object. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + * @throws OMEROServerError If the thread was interrupted. + * @throws InterruptedException If block(long) does not return. + */ + public void delete(Collection> objects) + throws ServiceException, AccessException, ExecutionException, OMEROServerError, InterruptedException { + for (GenericObjectWrapper object : objects) { + if (object instanceof FolderWrapper) { + ((FolderWrapper) object).unlinkAllROI(this); + } + } + if (!objects.isEmpty()) { + delete(objects.stream().map(GenericObjectWrapper::asIObject).collect(Collectors.toList())); + } + } + + /** * Deletes an object from OMERO. * diff --git a/src/main/java/fr/igred/omero/GatewayWrapper.java b/src/main/java/fr/igred/omero/GatewayWrapper.java index 57cdd5fd..efeab9f9 100644 --- a/src/main/java/fr/igred/omero/GatewayWrapper.java +++ b/src/main/java/fr/igred/omero/GatewayWrapper.java @@ -424,6 +424,28 @@ void delete(IObject object) } + /** + * Deletes multiple objects from OMERO. + * + * @param objects The OMERO objects. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + * @throws OMEROServerError If the thread was interrupted. + * @throws InterruptedException If block(long) does not return. + */ + void delete(List objects) + throws ServiceException, AccessException, ExecutionException, OMEROServerError, InterruptedException { + final int ms = 500; + try { + getDm().delete(ctx, objects).loop(10, ms); + } catch (DSOutOfServiceException | DSAccessException | LockTimeout e) { + handleException(e, "Cannot delete objects"); + } + } + + /** * Deletes a file from OMERO * diff --git a/src/main/java/fr/igred/omero/GenericObjectWrapper.java b/src/main/java/fr/igred/omero/GenericObjectWrapper.java index d4129b3a..2c5286c8 100644 --- a/src/main/java/fr/igred/omero/GenericObjectWrapper.java +++ b/src/main/java/fr/igred/omero/GenericObjectWrapper.java @@ -28,6 +28,7 @@ import omero.model.IObject; import java.sql.Timestamp; +import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; @@ -113,6 +114,29 @@ protected static void delete(Client client, IObject object) } + /** + * Only keeps objects with different IDs in a collection. + * + * @param objects A collection of objects. + * @param The objects type. + * + * @return Distinct objects list, sorted by ID. + */ + public static > List distinct(Collection objects) { + Collection ids = new ArrayList<>(objects.size()); + + List purged = new ArrayList<>(objects.size()); + for (T image : objects) { + if (!ids.contains(image.getId())) { + ids.add(image.getId()); + purged.add(image); + } + } + purged.sort(Comparator.comparing(T::getId)); + return purged; + } + + /** * Returns the contained DataObject as IObject. * diff --git a/src/main/java/fr/igred/omero/annotations/FileAnnotationWrapper.java b/src/main/java/fr/igred/omero/annotations/FileAnnotationWrapper.java index c679d72d..eee75e10 100644 --- a/src/main/java/fr/igred/omero/annotations/FileAnnotationWrapper.java +++ b/src/main/java/fr/igred/omero/annotations/FileAnnotationWrapper.java @@ -23,6 +23,7 @@ import omero.ServerError; import omero.api.RawFileStorePrx; import omero.gateway.exception.DSOutOfServiceException; +import omero.gateway.model.AnnotationData; import omero.gateway.model.FileAnnotationData; import java.io.File; @@ -44,51 +45,108 @@ public FileAnnotationWrapper(FileAnnotationData annotation) { } + /** + * Returns the format of the original file. + * + * @return See above. + */ public String getOriginalMimetype() { return data.getOriginalMimetype(); } + /** + * Returns the file format as defined by the specification, corresponding to the file extension. + * + * @return See above. + */ public String getServerFileMimetype() { return data.getServerFileMimetype(); } + /** + * Returns the format of the uploaded file. + * + * @return See above. + */ public String getFileFormat() { return data.getFileFormat(); } + /** + * Returns a user readable description of the file. + * + * @return See above. + */ public String getFileKind() { return data.getFileKind(); } + /** + * Returns the file to upload to the server. + * + * @return See above. + */ public File getAttachedFile() { return data.getAttachedFile(); } + /** + * Returns the name of the file. + * + * @return See above. + */ public String getFileName() { return data.getFileName(); } + /** + * Returns the absolute path to the file. + * + * @return See above. + */ public String getFilePath() { return data.getFilePath(); } + /** + * Returns the size of the file. + * + * @return See above. + */ public long getFileSize() { return data.getFileSize(); } + /** + * Returns the id of the file. + * + * @return See above. + */ public long getFileID() { return data.getFileID(); } + /** + * Returns the original file. + * + * @param client The client handling the connection. + * @param path The path where the file will be saved. + * + * @return See above. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws IOException Cannot write to the file. + * @throws OMEROServerError Server error. + */ public File getFile(Client client, String path) throws IOException, ServiceException, OMEROServerError { final int inc = 262144; @@ -121,11 +179,23 @@ public File getFile(Client client, String path) throws IOException, ServiceExcep } + /** + * Returns the absolute path to the file + * + * @return See above. + * + * @see AnnotationData#getContentAsString() + */ public String getContentAsString() { return data.getContentAsString(); } + /** + * Returns {@code true} if it is a movie file. {@code false} otherwise. + * + * @return See above. + */ public boolean isMovieFile() { return data.isMovieFile(); } diff --git a/src/main/java/fr/igred/omero/annotations/GenericAnnotationWrapper.java b/src/main/java/fr/igred/omero/annotations/GenericAnnotationWrapper.java index 2a0a0198..e81ad8c0 100644 --- a/src/main/java/fr/igred/omero/annotations/GenericAnnotationWrapper.java +++ b/src/main/java/fr/igred/omero/annotations/GenericAnnotationWrapper.java @@ -107,6 +107,22 @@ public void setDescription(String description) { } + /** + * Returns the number of annotations links for this object. + * + * @param client The client handling the connection. + * + * @return See above. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws OMEROServerError Server error. + */ + public int countAnnotationLinks(Client client) throws ServiceException, OMEROServerError { + return client.findByQuery("select link.parent from ome.model.IAnnotationLink link " + + "where link.child.id=" + getId()).size(); + } + + /** * Gets all projects with this tag from OMERO. * diff --git a/src/main/java/fr/igred/omero/annotations/TableWrapper.java b/src/main/java/fr/igred/omero/annotations/TableWrapper.java index 42294072..43bd257e 100644 --- a/src/main/java/fr/igred/omero/annotations/TableWrapper.java +++ b/src/main/java/fr/igred/omero/annotations/TableWrapper.java @@ -222,13 +222,13 @@ private static boolean isColumnNumeric(Variable[] resultsColumn) { /** - * Rename {@value IMAGE} column if it already exists to: + * Rename the {@value IMAGE} column if it already exists to: *
    *
  • "{@value LABEL} if the column does not exist
  • *
  • {@code "Image_column_" + columnNumber} otherwise
  • *
* - * @param results The results table to process. + * @param results The ResultsTable to process. */ private static void renameImageColumn(ResultsTable results) { if (results.columnExists(IMAGE)) { diff --git a/src/main/java/fr/igred/omero/repository/DatasetWrapper.java b/src/main/java/fr/igred/omero/repository/DatasetWrapper.java index 7e74c200..c67d3ca9 100644 --- a/src/main/java/fr/igred/omero/repository/DatasetWrapper.java +++ b/src/main/java/fr/igred/omero/repository/DatasetWrapper.java @@ -204,7 +204,7 @@ public List getImages(Client client) throws ServiceException, Acce /** - * Gets all images in the dataset with a certain from OMERO. + * Gets all images in the dataset with a certain name from OMERO. * * @param client The client handling the connection. * @param name Name searched. @@ -318,7 +318,7 @@ public List getImagesKey(Client client, String key) handleServiceOrAccess(e, "Cannot get images with key \"" + key + "\" from " + this); } - List selected = new ArrayList<>(); + List selected = new ArrayList<>(images.size()); for (ImageData image : images) { ImageWrapper imageWrapper = new ImageWrapper(image); @@ -357,7 +357,7 @@ public List getImagesPairKeyValue(Client client, String key, Strin handleServiceOrAccess(e, "Cannot get images with key-value pair from " + this); } - List selected = new ArrayList<>(); + List selected = new ArrayList<>(images.size()); for (ImageData image : images) { ImageWrapper imageWrapper = new ImageWrapper(image); @@ -534,12 +534,56 @@ public List importImage(Client client, String path) } + /** + * Replaces (and unlinks) a collection of images from this dataset by a new image, after copying their annotations + * and ROIs, and concatenating the descriptions (on new lines). + * + * @param client The client handling the connection. + * @param oldImages The list of old images to replace. + * @param newImage The new image. + * + * @return The list of images that became orphaned once replaced. + * + * @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. + * @throws InterruptedException If block(long) does not return. + */ + public List replaceImages(Client client, + Collection oldImages, + ImageWrapper newImage) + throws AccessException, ServiceException, ExecutionException, OMEROServerError, InterruptedException { + Collection descriptions = new ArrayList<>(oldImages.size() + 1); + List orphaned = new ArrayList<>(oldImages.size()); + descriptions.add(newImage.getDescription()); + for (ImageWrapper oldImage : oldImages) { + descriptions.add(oldImage.getDescription()); + newImage.copyAnnotationLinks(client, oldImage); + List rois = oldImage.getROIs(client); + for (ROIWrapper roi : rois) { + roi.setImage(newImage); + newImage.saveROI(client, roi); + } + this.removeImage(client, oldImage); + if (oldImage.isOrphaned(client)) { + orphaned.add(oldImage); + } + } + descriptions.removeIf(s -> s == null || s.trim().isEmpty()); + newImage.setDescription(String.join("\n", descriptions)); + newImage.saveAndUpdate(client); + return orphaned; + } + + /** * Imports one image file to the dataset in OMERO and replace older images sharing the same name after copying their - * annotations and ROIs, and concatenating the descriptions (on new lines). + * annotations and ROIs, and concatenating the descriptions (on new lines) by unlinking or even deleting them. * * @param client The client handling the connection. * @param path Path to the image on the computer. + * @param policy Whether older images should be unlinked, deleted or deleted only if they become orphaned. * * @return The list of IDs of the newly imported images. * @@ -549,35 +593,61 @@ public List importImage(Client client, String path) * @throws ExecutionException A Facility can't be retrieved or instantiated. * @throws InterruptedException If block(long) does not return. */ - public List importAndReplaceImages(Client client, String path) + public List importAndReplaceImages(Client client, String path, ReplacePolicy policy) throws ServiceException, AccessException, OMEROServerError, ExecutionException, InterruptedException { List ids = importImage(client, path); Long[] newIds = ids.toArray(LONGS); - List newImages = client.getImages(newIds); + List newImages = client.getImages(newIds); + Collection toDelete = new ArrayList<>(newImages.size()); for (ImageWrapper image : newImages) { List oldImages = getImages(client, image.getName()); oldImages.removeIf(i -> ids.contains(i.getId())); - ArrayList descriptions = new ArrayList<>(oldImages.size() + 1); - descriptions.add(image.getDescription()); - for (ImageWrapper oldImage : oldImages) { - descriptions.add(oldImage.getDescription()); - image.copyAnnotationLinks(client, oldImage); - List rois = oldImage.getROIs(client); - for (ROIWrapper roi : rois) { - roi.setImage(image); - image.saveROI(client, roi); + List orphaned = replaceImages(client, oldImages, image); + if (policy == ReplacePolicy.DELETE) { + toDelete.addAll(oldImages); + } else if (policy == ReplacePolicy.DELETE_ORPHANED) { + toDelete.addAll(orphaned); + } + } + if (policy == ReplacePolicy.DELETE_ORPHANED) { + List idsToDelete = toDelete.stream().map(GenericObjectWrapper::getId).collect(Collectors.toList()); + + Iterable orphans = new ArrayList<>(toDelete); + for (ImageWrapper orphan : orphans) { + for (ImageWrapper other : orphan.getFilesetImages(client)) { + if (!idsToDelete.contains(other.getId()) && other.isOrphaned(client)) { + toDelete.add(other); + } } - client.delete(oldImage); } - descriptions.removeIf(s -> s == null || s.trim().isEmpty()); - image.setDescription(String.join("\n", descriptions)); - image.saveAndUpdate(client); } + client.delete(toDelete); return ids; } + /** + * Imports one image file to the dataset in OMERO and replace older images sharing the same name after copying their + * annotations and ROIs, and concatenating the descriptions (on new lines) by unlinking them. + * + * @param client The client handling the connection. + * @param path Path to the image 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. + * @throws InterruptedException If block(long) does not return. + */ + public List importAndReplaceImages(Client client, String path) + throws ServiceException, AccessException, OMEROServerError, ExecutionException, InterruptedException { + return importAndReplaceImages(client, path, ReplacePolicy.UNLINK); + } + + /** * Refreshes the wrapped dataset. * diff --git a/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java b/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java index ca38f3b2..18e432f9 100644 --- a/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java +++ b/src/main/java/fr/igred/omero/repository/GenericRepositoryObjectWrapper.java @@ -433,7 +433,7 @@ public TableWrapper getTable(Client client, Long fileId) * * @param client The client handling the connection. * - * @return List of TableWrapper containing the tables information. + * @return List of TableWrappers containing the tables. * * @throws ServiceException Cannot connect to OMERO. * @throws AccessException Cannot access data. @@ -460,7 +460,7 @@ public List getTables(Client client) /** - * Links a file to the object + * Uploads a file and links it to the object * * @param client The client handling the connection. * @param file File to add. @@ -480,6 +480,65 @@ public long addFile(Client client, File file) throws ExecutionException, Interru } + /** + * Uploads a file, links it to the object and unlinks previous files with the same name, or deletes them. + * + * @param client The client handling the connection. + * @param file File to add. + * @param policy Whether older files should be unlinked, deleted or deleted only if they become orphaned. + * + * @return ID of the file created in OMERO. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + * @throws InterruptedException The thread was interrupted. + * @throws OMEROServerError If the thread was interrupted. + */ + public long addAndReplaceFile(Client client, File file, ReplacePolicy policy) + throws ExecutionException, InterruptedException, AccessException, ServiceException, OMEROServerError { + List files = getFileAnnotations(client); + + FileAnnotationData uploaded = client.getDm().attachFile(client.getCtx(), + file, + null, + "", + file.getName(), + data).get(); + FileAnnotationWrapper annotation = new FileAnnotationWrapper(uploaded); + + files.removeIf(f -> !f.getFileName().equals(annotation.getFileName())); + for (FileAnnotationWrapper f : files) { + this.unlink(client, f); + if (policy == ReplacePolicy.DELETE || + policy == ReplacePolicy.DELETE_ORPHANED && f.countAnnotationLinks(client) == 0) { + client.deleteFile(f.getId()); + } + } + return annotation.getFileID(); + } + + + /** + * Uploads a file, links it to the object and unlinks previous files with the same name, or deletes them. + * + * @param client The client handling the connection. + * @param file File to add. + * + * @return ID of the file created in OMERO. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + * @throws InterruptedException The thread was interrupted. + * @throws OMEROServerError If the thread was interrupted. + */ + public long addAndReplaceFile(Client client, File file) + throws ExecutionException, InterruptedException, AccessException, ServiceException, OMEROServerError { + return addAndReplaceFile(client, file, ReplacePolicy.UNLINK); + } + + /** * Links a file annotation to the object * @@ -621,4 +680,18 @@ public void copyAnnotationLinks(Client client, GenericRepositoryObjectWrapper } + /** + * Policy to specify how to handle objects when they are replaced. + */ + public enum ReplacePolicy { + /** Unlink objects only */ + UNLINK, + + /** Delete all objects */ + DELETE, + + /** Delete orphaned objects */ + DELETE_ORPHANED + } + } diff --git a/src/main/java/fr/igred/omero/repository/ImageWrapper.java b/src/main/java/fr/igred/omero/repository/ImageWrapper.java index 6993b45d..fc3bdf0d 100644 --- a/src/main/java/fr/igred/omero/repository/ImageWrapper.java +++ b/src/main/java/fr/igred/omero/repository/ImageWrapper.java @@ -208,6 +208,51 @@ public List getDatasets(Client client) } + /** + * Checks if image is orphaned (not in a WellSample nor linked to a dataset). + * + * @param client The client handling the connection. + * + * @return {@code true} if the image is orphaned, {@code false} otherwise. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws OMEROServerError Server error. + */ + public boolean isOrphaned(Client client) throws ServiceException, OMEROServerError { + boolean noDataset = client.findByQuery("select link.parent from DatasetImageLink link " + + "where link.child=" + getId()).isEmpty(); + boolean noWell = client.findByQuery("select ws from WellSample ws where image=" + getId()).isEmpty(); + return noDataset && noWell; + } + + + /** + * Returns the list of images sharing the same fileset as the current image. + * + * @param client The client handling the connection. + * + * @return See above. + * + * @throws AccessException Cannot access data. + * @throws ServiceException Cannot connect to OMERO. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + * @throws OMEROServerError Server error. + */ + public List getFilesetImages(Client client) + throws AccessException, ServiceException, ExecutionException, OMEROServerError { + List related = new ArrayList<>(0); + if (data.isFSImage()) { + long fsId = this.asImageData().getFilesetId(); + + List objects = client.findByQuery("select i from Image i where fileset=" + fsId); + + Long[] ids = objects.stream().map(IObject::getId).map(RLong::getValue).sorted().toArray(Long[]::new); + related = client.getImages(ids); + } + return related; + } + + /** * Links a ROI to the image in OMERO *

DO NOT USE IT IF A SHAPE WAS DELETED !!! diff --git a/src/main/java/fr/igred/omero/repository/PlateWrapper.java b/src/main/java/fr/igred/omero/repository/PlateWrapper.java index 18157487..8c6c09d7 100644 --- a/src/main/java/fr/igred/omero/repository/PlateWrapper.java +++ b/src/main/java/fr/igred/omero/repository/PlateWrapper.java @@ -245,7 +245,7 @@ public String getPlateType() { /** * Returns the x-coordinate in 2D-space of the well. * - * @param unit The unit (may be null, in which case no conversion will be performed) + * @param unit The unit (can be null, in which case no conversion will be performed) * * @return See above * @@ -259,7 +259,7 @@ public Length getWellOriginX(UnitsLength unit) throws BigResult { /** * Returns the y-coordinate in 2D-space of the well. * - * @param unit The unit (may be null, in which case no conversion will be performed) + * @param unit The unit (can be null, in which case no conversion will be performed) * * @return See above * diff --git a/src/main/java/fr/igred/omero/repository/ProjectWrapper.java b/src/main/java/fr/igred/omero/repository/ProjectWrapper.java index f43bd26e..6f6660f9 100644 --- a/src/main/java/fr/igred/omero/repository/ProjectWrapper.java +++ b/src/main/java/fr/igred/omero/repository/ProjectWrapper.java @@ -36,6 +36,7 @@ import java.util.Comparator; import java.util.List; import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; import static fr.igred.omero.exception.ExceptionHandler.handleServiceOrAccess; @@ -79,22 +80,6 @@ public ProjectWrapper(Client client, String name, String description) } - /** - * Only keep images with different IDs in a collection. - * - * @return ImageWrapper list. - */ - private static List purge(Collection images) { - List purged = new ArrayList<>(images.size()); - for (ImageWrapper image : images) { - if (purged.isEmpty() || purged.get(purged.size() - 1).getId() != image.getId()) { - purged.add(image); - } - } - return purged; - } - - /** * Gets the ProjectData name * @@ -262,18 +247,21 @@ public void removeDataset(Client client, DatasetWrapper dataset) public List getImages(Client client) throws ServiceException, AccessException, ExecutionException { Collection datasets = getDatasets(); - List images = new ArrayList<>(); + Collection> lists = new ArrayList<>(datasets.size()); for (DatasetWrapper dataset : datasets) { - images.addAll(dataset.getImages(client)); + lists.add(dataset.getImages(client)); } - images.sort(Comparator.comparing(GenericObjectWrapper::getId)); + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); - return purge(images); + return distinct(images); } /** - * Gets all images in the project with a certain from OMERO. + * Gets all images in the project with a certain name from OMERO. * * @param client The client handling the connection. * @param name Name searched. @@ -288,13 +276,46 @@ public List getImages(Client client, String name) throws ServiceException, AccessException, ExecutionException { Collection datasets = getDatasets(); - List images = new ArrayList<>(); + Collection> lists = new ArrayList<>(datasets.size()); for (DatasetWrapper dataset : datasets) { - images.addAll(dataset.getImages(client, name)); + lists.add(dataset.getImages(client, name)); } - images.sort(Comparator.comparing(GenericObjectWrapper::getId)); + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); - return purge(images); + return distinct(images); + } + + + /** + * Gets all images with a certain name from datasets with the specified name inside this project on OMERO. + * + * @param client The client handling the connection. + * @param datasetName Expected dataset name. + * @param imageName Expected image name. + * + * @return ImageWrapper list. + * + * @throws ServiceException Cannot connect to OMERO. + * @throws AccessException Cannot access data. + * @throws ExecutionException A Facility can't be retrieved or instantiated. + */ + public List getImages(Client client, String datasetName, String imageName) + throws ServiceException, AccessException, ExecutionException { + Collection datasets = getDatasets(datasetName); + + Collection> lists = new ArrayList<>(datasets.size()); + for (DatasetWrapper dataset : datasets) { + lists.add(dataset.getImages(client, imageName)); + } + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); + + return distinct(images); } @@ -312,13 +333,18 @@ public List getImages(Client client, String name) */ public List getImagesLike(Client client, String motif) throws ServiceException, AccessException, ExecutionException { - List images = new ArrayList<>(); - for (DatasetWrapper dataset : getDatasets()) { - images.addAll(dataset.getImagesLike(client, motif)); + Collection datasets = getDatasets(); + + Collection> lists = new ArrayList<>(datasets.size()); + for (DatasetWrapper dataset : datasets) { + lists.add(dataset.getImagesLike(client, motif)); } - images.sort(Comparator.comparing(GenericObjectWrapper::getId)); + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); - return purge(images); + return distinct(images); } @@ -337,13 +363,18 @@ public List getImagesLike(Client client, String motif) */ public List getImagesTagged(Client client, TagAnnotationWrapper tag) throws ServiceException, AccessException, OMEROServerError, ExecutionException { - List images = new ArrayList<>(); - for (DatasetWrapper dataset : getDatasets()) { - images.addAll(dataset.getImagesTagged(client, tag)); + Collection datasets = getDatasets(); + + Collection> lists = new ArrayList<>(datasets.size()); + for (DatasetWrapper dataset : datasets) { + lists.add(dataset.getImagesTagged(client, tag)); } - images.sort(Comparator.comparing(GenericObjectWrapper::getId)); + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); - return purge(images); + return distinct(images); } @@ -362,13 +393,18 @@ public List getImagesTagged(Client client, TagAnnotationWrapper ta */ public List getImagesTagged(Client client, Long tagId) throws ServiceException, AccessException, OMEROServerError, ExecutionException { - List images = new ArrayList<>(); - for (DatasetWrapper dataset : getDatasets()) { - images.addAll(dataset.getImagesTagged(client, tagId)); + Collection datasets = getDatasets(); + + Collection> lists = new ArrayList<>(datasets.size()); + for (DatasetWrapper dataset : datasets) { + lists.add(dataset.getImagesTagged(client, tagId)); } - images.sort(Comparator.comparing(GenericObjectWrapper::getId)); + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); - return purge(images); + return distinct(images); } @@ -386,13 +422,18 @@ public List getImagesTagged(Client client, Long tagId) */ public List getImagesKey(Client client, String key) throws ServiceException, AccessException, ExecutionException { - List images = new ArrayList<>(); - for (DatasetWrapper dataset : getDatasets()) { - images.addAll(dataset.getImagesKey(client, key)); + Collection datasets = getDatasets(); + + Collection> lists = new ArrayList<>(datasets.size()); + for (DatasetWrapper dataset : datasets) { + lists.add(dataset.getImagesKey(client, key)); } - images.sort(Comparator.comparing(GenericObjectWrapper::getId)); + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); - return purge(images); + return distinct(images); } @@ -411,13 +452,18 @@ public List getImagesKey(Client client, String key) */ public List getImagesPairKeyValue(Client client, String key, String value) throws ServiceException, AccessException, ExecutionException { - List images = new ArrayList<>(); - for (DatasetWrapper dataset : getDatasets()) { - images.addAll(dataset.getImagesPairKeyValue(client, key, value)); + Collection datasets = getDatasets(); + + Collection> lists = new ArrayList<>(datasets.size()); + for (DatasetWrapper dataset : datasets) { + lists.add(dataset.getImagesPairKeyValue(client, key, value)); } - images.sort(Comparator.comparing(GenericObjectWrapper::getId)); + List images = lists.stream() + .flatMap(Collection::stream) + .sorted(Comparator.comparing(GenericObjectWrapper::getId)) + .collect(Collectors.toList()); - return purge(images); + return distinct(images); } diff --git a/src/main/java/fr/igred/omero/repository/WellSampleWrapper.java b/src/main/java/fr/igred/omero/repository/WellSampleWrapper.java index c2953559..bcfb2155 100644 --- a/src/main/java/fr/igred/omero/repository/WellSampleWrapper.java +++ b/src/main/java/fr/igred/omero/repository/WellSampleWrapper.java @@ -68,7 +68,7 @@ public void setImage(ImageWrapper image) { /** * Returns the position X. * - * @param unit The unit (may be null, in which case no conversion will be performed) + * @param unit The unit (can be null, in which case no conversion will be performed) * * @return See above. * @@ -82,7 +82,7 @@ public Length getPositionX(UnitsLength unit) throws BigResult { /** * Returns the position Y. * - * @param unit The unit (may be null, in which case no conversion will be performed) + * @param unit The unit (can be null, in which case no conversion will be performed) * * @return See above. * diff --git a/src/main/java/fr/igred/omero/roi/ROIWrapper.java b/src/main/java/fr/igred/omero/roi/ROIWrapper.java index 19caead9..3b9892f3 100644 --- a/src/main/java/fr/igred/omero/roi/ROIWrapper.java +++ b/src/main/java/fr/igred/omero/roi/ROIWrapper.java @@ -93,7 +93,7 @@ public ROIWrapper(ROIData data) { * * @param property The property where 4D ROI local ID is stored. * - * @return The property, or the default value {@link #IJ_PROPERTY} (= {@value #IJ_PROPERTY}) if it is null or empty. + * @return The property, or the default value {@link #IJ_PROPERTY} (= {@value IJ_PROPERTY}) if it is null or empty. */ public static String checkProperty(String property) { if (property == null || property.trim().isEmpty()) return IJ_PROPERTY; @@ -104,8 +104,7 @@ public static String checkProperty(String property) { /** * Returns ID property corresponding to input local ID property (appends "_ID" to said property). * - * @param property The property where 4D ROI local ID is stored, defaults to {@value #IJ_PROPERTY} if null or - * empty. + * @param property The property where 4D ROI local ID is stored, defaults to {@value IJ_PROPERTY} if null or empty. * * @return See above. */ @@ -131,8 +130,7 @@ public static List fromImageJ(List ijRois) { * Converts an ImageJ list of ROIs to a list of OMERO ROIs * * @param ijRois A list of ImageJ ROIs. - * @param property The property where 4D ROI local ID is stored. Defaults to {@value #IJ_PROPERTY} if null or - * empty. + * @param property The property where 4D ROI local ID is stored. Defaults to {@value IJ_PROPERTY} if null or empty. * * @return The converted list of OMERO ROIs. */ @@ -178,8 +176,7 @@ public static List toImageJ(List rois) { * Converts an OMERO list of ROIs to a list of ImageJ ROIs * * @param rois A list of OMERO ROIs. - * @param property The property where 4D ROI local ID will be stored. Defaults to {@value #IJ_PROPERTY} if null or - * empty. + * @param property The property used to store 4D ROI local IDs. Defaults to {@value IJ_PROPERTY} if null or empty. * * @return The converted list of ImageJ ROIs. */ diff --git a/src/main/java/fr/igred/omero/roi/ShapeList.java b/src/main/java/fr/igred/omero/roi/ShapeList.java index 2b72f862..9a43bbb2 100644 --- a/src/main/java/fr/igred/omero/roi/ShapeList.java +++ b/src/main/java/fr/igred/omero/roi/ShapeList.java @@ -59,7 +59,7 @@ public > List getElementsOf(Class projects = new ArrayList<>(2); + projects.add(new ProjectWrapper(projectData1)); + projects.add(new ProjectWrapper(projectData2)); + sudo.delete(projects); + } + + // This test returns a ServiceException for a "security violation". @Test(expected = ServiceException.class) public void testSudoFailGetDatasets() throws Exception { diff --git a/src/test/java/fr/igred/omero/BasicTest.java b/src/test/java/fr/igred/omero/BasicTest.java index de8ac1a4..17e389d0 100644 --- a/src/test/java/fr/igred/omero/BasicTest.java +++ b/src/test/java/fr/igred/omero/BasicTest.java @@ -24,7 +24,13 @@ import org.junit.rules.TestWatcher; import org.junit.runner.Description; +import java.io.File; +import java.io.IOException; +import java.io.PrintStream; import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.security.SecureRandom; import java.util.logging.Logger; @@ -89,7 +95,7 @@ protected void starting(Description description) { @Override protected void skipped(AssumptionViolatedException e, Description description) { float time = (float) (System.currentTimeMillis() - getStart()) / 1000; - String status = ANSI_YELLOW + "SKIPPED" + ANSI_RESET; + String status = String.format("%sSKIPPED%s", ANSI_YELLOW, ANSI_RESET); String testName = description.getMethodName() + ":"; logger.info(String.format("%-40s\t%s (%.3f s)", testName, status, time)); } @@ -98,7 +104,7 @@ protected void skipped(AssumptionViolatedException e, Description description) { @Override protected void succeeded(Description description) { float time = (float) (System.currentTimeMillis() - getStart()) / 1000; - String status = ANSI_GREEN + "SUCCEEDED" + ANSI_RESET; + String status = String.format("%sSUCCEEDED%s", ANSI_GREEN, ANSI_RESET); String testName = description.getMethodName() + ":"; logger.info(String.format("%-40s\t%s (%.3f s)", testName, status, time)); } @@ -108,10 +114,41 @@ protected void succeeded(Description description) { protected void failed(Throwable e, Description description) { float time = (float) (System.currentTimeMillis() - getStart()) / 1000; String testName = description.getMethodName() + ":"; - String status = ANSI_RED + "FAILED" + ANSI_RESET; + String status = String.format("%sFAILED%s", ANSI_RED, ANSI_RESET); logger.info(String.format("%-40s\t%s (%.3f s)", testName, status, time)); } } + + protected static File createFile(String filename) throws IOException { + final String tmpdir = System.getProperty("java.io.tmpdir") + File.separator; + + File file = new File(tmpdir + File.separator + filename); + if (!file.createNewFile()) { + System.err.println("\"" + file.getCanonicalPath() + "\" could not be created."); + } + return file; + } + + + protected static File createRandomFile(String filename) throws IOException { + File file = createFile(filename); + + final byte[] array = new byte[2 * 262144 + 20]; + new SecureRandom().nextBytes(array); + String generatedString = new String(array, StandardCharsets.UTF_8); + try (PrintStream out = new PrintStream(Files.newOutputStream(file.toPath()), false, "UTF-8")) { + out.print(generatedString); + } + return file; + } + + + protected static void removeFile(File file) throws IOException { + if (!file.delete()) { + System.err.println("\"" + file.getCanonicalPath() + "\" could not be deleted."); + } + } + } diff --git a/src/test/java/fr/igred/omero/ClientTest.java b/src/test/java/fr/igred/omero/ClientTest.java index 0e773f5d..649177cc 100644 --- a/src/test/java/fr/igred/omero/ClientTest.java +++ b/src/test/java/fr/igred/omero/ClientTest.java @@ -220,9 +220,7 @@ public void testSwitchGroupAndImport() throws Exception { String filename = "8bit-unsigned&pixelType=uint8&sizeZ=3&sizeC=5&sizeT=7&sizeX=256&sizeY=256.fake"; - File f = new File("." + File.separator + filename); - if (!f.createNewFile()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be created."); + File f = createFile(filename); client.switchGroup(newGroupId); @@ -231,8 +229,7 @@ public void testSwitchGroupAndImport() throws Exception { List ids = dataset.importImage(client, f.getAbsolutePath()); - if (!f.delete()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be deleted."); + removeFile(f); assertEquals(1, ids.size()); diff --git a/src/test/java/fr/igred/omero/RootTest.java b/src/test/java/fr/igred/omero/RootTest.java index dee7a105..4cd76442 100644 --- a/src/test/java/fr/igred/omero/RootTest.java +++ b/src/test/java/fr/igred/omero/RootTest.java @@ -40,7 +40,7 @@ public void setUp() { assertEquals("Wrong group", GROUP1.id, client.getCurrentGroupId()); } catch (Exception e) { failed = true; - logger.log(Level.SEVERE, ANSI_RED + "Connection failed." + ANSI_RESET, e); + logger.log(Level.SEVERE, String.format("%sConnection failed.%s", ANSI_RED, ANSI_RESET), e); } org.junit.Assume.assumeFalse(failed); } @@ -51,7 +51,7 @@ public void cleanUp() { try { client.disconnect(); } catch (Exception e) { - logger.log(Level.WARNING, ANSI_YELLOW + "Disconnection failed." + ANSI_RESET, e); + logger.log(Level.WARNING, String.format("%sDisconnection failed.%s", ANSI_YELLOW, ANSI_RESET), e); } } diff --git a/src/test/java/fr/igred/omero/SudoTest.java b/src/test/java/fr/igred/omero/SudoTest.java index 0fcf1722..591522b7 100644 --- a/src/test/java/fr/igred/omero/SudoTest.java +++ b/src/test/java/fr/igred/omero/SudoTest.java @@ -81,9 +81,7 @@ public void sudoImport() throws Exception { assertEquals(4L, client3.getId()); client3.switchGroup(6L); - File f = new File("." + File.separator + filename); - if (!f.createNewFile()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be created."); + File f = createFile(filename); DatasetWrapper dataset = new DatasetWrapper("sudoTest", ""); dataset.saveAndUpdate(client3); @@ -91,8 +89,7 @@ public void sudoImport() throws Exception { assertTrue(dataset.canLink()); dataset.importImages(client3, f.getAbsolutePath()); - if (!f.delete()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be deleted."); + removeFile(f); List images = dataset.getImages(client3); assertEquals(1, images.size()); diff --git a/src/test/java/fr/igred/omero/TestObject.java b/src/test/java/fr/igred/omero/TestObject.java index 823cef34..88a8e503 100644 --- a/src/test/java/fr/igred/omero/TestObject.java +++ b/src/test/java/fr/igred/omero/TestObject.java @@ -29,4 +29,14 @@ public class TestObject { this.description = description; } + + @Override + public String toString() { + return "TestObject{" + + "id=" + id + + ", name='" + name + '\'' + + ", description='" + description + '\'' + + '}'; + } + } diff --git a/src/test/java/fr/igred/omero/UserTest.java b/src/test/java/fr/igred/omero/UserTest.java index 06c95de6..5ffe298a 100644 --- a/src/test/java/fr/igred/omero/UserTest.java +++ b/src/test/java/fr/igred/omero/UserTest.java @@ -40,7 +40,7 @@ public void setUp() { assertEquals("Wrong group", GROUP1.id, client.getCurrentGroupId()); } catch (Exception e) { failed = true; - logger.log(Level.SEVERE, ANSI_RED + "Connection failed." + ANSI_RESET, e); + logger.log(Level.SEVERE, String.format("%sConnection failed.%s", ANSI_RED, ANSI_RESET), e); } org.junit.Assume.assumeFalse(failed); } @@ -51,7 +51,7 @@ public void cleanUp() { try { client.disconnect(); } catch (RuntimeException e) { - logger.log(Level.WARNING, ANSI_YELLOW + "Disconnection failed." + ANSI_RESET, e); + logger.log(Level.WARNING, String.format("%sDisconnection failed.%s", ANSI_YELLOW, ANSI_RESET), e); } } diff --git a/src/test/java/fr/igred/omero/repository/DatasetTest.java b/src/test/java/fr/igred/omero/repository/DatasetTest.java index 7ac0cc88..00422322 100644 --- a/src/test/java/fr/igred/omero/repository/DatasetTest.java +++ b/src/test/java/fr/igred/omero/repository/DatasetTest.java @@ -21,10 +21,6 @@ import org.junit.Test; import java.io.File; -import java.io.FileOutputStream; -import java.io.PrintStream; -import java.nio.charset.StandardCharsets; -import java.security.SecureRandom; import java.util.List; import java.util.NoSuchElementException; @@ -346,23 +342,10 @@ public void testGetImagesFromDataset() throws Exception { public void testAddFileDataset() throws Exception { DatasetWrapper dataset = client.getDataset(DATASET1.id); - File file = new File("." + File.separator + "test.txt"); - if (!file.createNewFile()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be created."); - - final byte[] array = new byte[2 * 262144 + 20]; - new SecureRandom().nextBytes(array); - String generatedString = new String(array, StandardCharsets.UTF_8); - try (PrintStream out = new PrintStream(new FileOutputStream(file), false, "UTF-8")) { - out.print(generatedString); - } - - Long id = dataset.addFile(client, file); - if (!file.delete()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be deleted."); - + File file = createRandomFile("test_dataset.txt"); + Long id = dataset.addFile(client, file); + removeFile(file); client.deleteFile(id); - assertNotEquals(0L, id.longValue()); } diff --git a/src/test/java/fr/igred/omero/repository/FolderTest.java b/src/test/java/fr/igred/omero/repository/FolderTest.java index 96cac0c1..771a843c 100644 --- a/src/test/java/fr/igred/omero/repository/FolderTest.java +++ b/src/test/java/fr/igred/omero/repository/FolderTest.java @@ -170,9 +170,7 @@ public void testFolder3() throws Exception { assertEquals(2, folders.size()); assertEquals(nImages, image.getROIs(client).size()); - for (FolderWrapper roiFolder : folders) { - client.delete(roiFolder); - } + client.delete(folders); assertEquals(0, image.getFolders(client).size()); assertEquals(nImages, image.getROIs(client).size()); diff --git a/src/test/java/fr/igred/omero/repository/ImageTest.java b/src/test/java/fr/igred/omero/repository/ImageTest.java index ba7b6e18..ee340166 100644 --- a/src/test/java/fr/igred/omero/repository/ImageTest.java +++ b/src/test/java/fr/igred/omero/repository/ImageTest.java @@ -35,9 +35,6 @@ import java.awt.image.BufferedImage; import java.io.File; -import java.io.FileOutputStream; -import java.io.PrintStream; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.security.SecureRandom; import java.time.LocalDate; @@ -49,6 +46,8 @@ import java.util.Map; import java.util.Random; +import static fr.igred.omero.repository.GenericRepositoryObjectWrapper.ReplacePolicy.DELETE; +import static fr.igred.omero.repository.GenericRepositoryObjectWrapper.ReplacePolicy.DELETE_ORPHANED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -78,30 +77,18 @@ public void testImportImage() throws Exception { String filename1 = "8bit-unsigned&pixelType=uint8&sizeZ=5&sizeC=5&sizeT=7&sizeX=512&sizeY=512.fake"; String filename2 = "8bit-unsigned&pixelType=uint8&sizeZ=4&sizeC=5&sizeT=6&sizeX=512&sizeY=512.fake"; - File f1 = new File("." + File.separator + filename1); - if (!f1.createNewFile()) - System.err.println("\"" + f1.getCanonicalPath() + "\" could not be created."); - - File f2 = new File("." + File.separator + filename2); - if (!f2.createNewFile()) - System.err.println("\"" + f2.getCanonicalPath() + "\" could not be created."); + File f1 = createFile(filename1); + File f2 = createFile(filename2); DatasetWrapper dataset = client.getDataset(DATASET2.id); boolean imported = dataset.importImages(client, f1.getAbsolutePath(), f2.getAbsolutePath()); - if (!f1.delete()) - System.err.println("\"" + f1.getCanonicalPath() + "\" could not be deleted."); - - if (!f2.delete()) - System.err.println("\"" + f2.getCanonicalPath() + "\" could not be deleted."); + removeFile(f1); + removeFile(f2); List images = dataset.getImages(client); - - for (ImageWrapper image : images) { - client.delete(image); - } - + client.delete(images); List endImages = dataset.getImages(client); assertEquals(2, images.size()); @@ -114,17 +101,14 @@ public void testImportImage() throws Exception { public void testPairKeyValue() throws Exception { String filename = "8bit-unsigned&pixelType=uint8&sizeZ=3&sizeC=5&sizeT=7&sizeX=512&sizeY=512.fake"; - File f = new File("." + File.separator + filename); - if (!f.createNewFile()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be created."); + File f = createFile(filename); DatasetWrapper dataset = client.getDataset(DATASET2.id); List newIDs = dataset.importImage(client, f.getAbsolutePath()); assertEquals(1, newIDs.size()); - if (!f.delete()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be deleted."); + removeFile(f); List images = dataset.getImages(client); @@ -162,17 +146,11 @@ public void testPairKeyValue() throws Exception { public void testPairKeyValue2() throws Exception { String filename = "8bit-unsigned&pixelType=uint8&sizeZ=3&sizeC=5&sizeT=7&sizeX=512&sizeY=512.fake"; - File f = new File("." + File.separator + filename); - if (!f.createNewFile()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be created."); + File f = createFile(filename); DatasetWrapper dataset = client.getDataset(DATASET2.id); - dataset.importImages(client, f.getAbsolutePath()); - - if (!f.delete()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be deleted."); - + removeFile(f); List images = dataset.getImages(client); ImageWrapper image = images.get(0); @@ -201,17 +179,11 @@ public void testPairKeyValue3() throws Exception { String filename = "8bit-unsigned&pixelType=uint8&sizeZ=3&sizeC=5&sizeT=7&sizeX=512&sizeY=512.fake"; - File f = new File("." + File.separator + filename); - if (!f.createNewFile()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be created."); + File f = createFile(filename); DatasetWrapper dataset = client.getDataset(DATASET2.id); - dataset.importImages(client, f.getAbsolutePath()); - - if (!f.delete()) - System.err.println("\"" + f.getCanonicalPath() + "\" could not be deleted."); - + removeFile(f); List images = dataset.getImages(client); ImageWrapper image = images.get(0); @@ -383,15 +355,10 @@ public void testToImagePlusBound() throws Exception { tBound[1] = random.nextInt(5 - tBound[0]) + tBound[0] + 2; String fake = "8bit-unsigned&pixelType=uint8&sizeZ=3&sizeC=5&sizeT=7&sizeX=512&sizeY=512.fake"; - File fakeFile = new File(fake); - - if (!fakeFile.createNewFile()) - System.err.println("\"" + fakeFile.getCanonicalPath() + "\" could not be created."); + File fakeFile = createFile(fake); ImagePlus reference = BF.openImagePlus(fake)[0]; - - if (!fakeFile.delete()) - System.err.println("\"" + fakeFile.getCanonicalPath() + "\" could not be deleted."); + removeFile(fakeFile); Duplicator duplicator = new Duplicator(); reference.setRoi(xBound[0], yBound[0], xBound[1] - xBound[0] + 1, yBound[1] - yBound[0] + 1); @@ -418,17 +385,11 @@ public void testToImagePlusBound() throws Exception { @Test public void testToImagePlus() throws Exception { - String fake = "8bit-unsigned&pixelType=uint8&sizeZ=2&sizeC=5&sizeT=7&sizeX=512&sizeY=512.fake"; - - File fakeFile = new File(fake); - - if (!fakeFile.createNewFile()) - System.err.println("\"" + fakeFile.getCanonicalPath() + "\" could not be created."); + String fake = "8bit-unsigned&pixelType=uint8&sizeZ=2&sizeC=5&sizeT=7&sizeX=512&sizeY=512.fake"; + File fakeFile = createFile(fake); ImagePlus reference = BF.openImagePlus(fake)[0]; - - if (!fakeFile.delete()) - System.err.println("\"" + fakeFile.getCanonicalPath() + "\" could not be deleted."); + removeFile(fakeFile); ImageWrapper image = client.getImage(IMAGE2.id); @@ -586,22 +547,10 @@ public void testImageOrder() throws Exception { @Test public void testAddFileImage() throws Exception { - final String tmpdir = System.getProperty("java.io.tmpdir") + File.separator; - ImageWrapper image = client.getImage(IMAGE1.id); - File file = new File(tmpdir + "test.txt"); - if (!file.createNewFile()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be created."); - - final byte[] array = new byte[2 * 262144 + 20]; - new SecureRandom().nextBytes(array); - String generatedString = new String(array, StandardCharsets.UTF_8); - try (PrintStream out = new PrintStream(new FileOutputStream(file), false, "UTF-8")) { - out.print(generatedString); - } - - long id = image.addFile(client, file); + File file = createRandomFile("test_image.txt"); + long id = image.addFile(client, file); List files = image.getFileAnnotations(client); for (FileAnnotationWrapper f : files) { @@ -611,8 +560,8 @@ public void testAddFileImage() throws Exception { assertEquals("text/plain", f.getOriginalMimetype()); assertEquals("text/plain", f.getServerFileMimetype()); assertEquals("Plain Text Document", f.getFileKind()); - assertEquals(tmpdir, f.getContentAsString()); - assertEquals(tmpdir, f.getFilePath()); + assertEquals(file.getParent() + File.separator, f.getContentAsString()); + assertEquals(file.getParent() + File.separator, f.getFilePath()); assertFalse(f.isMovieFile()); File uploadedFile = f.getFile(client, "." + File.separator + "uploaded.txt"); @@ -623,16 +572,12 @@ public void testAddFileImage() throws Exception { for (int i = 0; i < expectedLines.size(); i++) { assertEquals(expectedLines.get(i), lines.get(i)); } - - if (!uploadedFile.delete()) - System.err.println("\"" + uploadedFile.getCanonicalPath() + "\" could not be deleted."); + removeFile(uploadedFile); } } client.deleteFile(id); - - if (!file.delete()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be deleted."); + removeFile(file); assertNotEquals(0L, id); } @@ -756,26 +701,14 @@ public void testDownload() throws Exception { @Test - public void testImportAndRenameImages() throws Exception { - String filename = "8bit-unsigned&pixelType=uint8&sizeZ=5&sizeC=5&sizeT=7&sizeX=512&sizeY=512.fake"; + public void testReplaceAndDeleteImages() throws Exception { + String filename = "8bit-unsigned&pixelType=uint8&sizeZ=5&sizeC=5&sizeX=512&sizeY=512.fake"; DatasetWrapper dataset = new DatasetWrapper("Test Import & Replace", ""); client.getProject(PROJECT1.id).addDataset(client, dataset); - File imageFile = new File("." + File.separator + filename); - if (!imageFile.createNewFile()) - System.err.println("\"" + imageFile.getCanonicalPath() + "\" could not be created."); - - File file = new File("." + File.separator + "test.txt"); - if (!file.createNewFile()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be created."); - - final byte[] array = new byte[2 * 262144 + 20]; - new SecureRandom().nextBytes(array); - String generatedString = new String(array, StandardCharsets.UTF_8); - try (PrintStream out = new PrintStream(new FileOutputStream(file), false, "UTF-8")) { - out.print(generatedString); - } + File imageFile = createFile(filename); + File file = createRandomFile("test_image.txt"); List ids1 = dataset.importImage(client, imageFile.getAbsolutePath()); ImageWrapper image1 = client.getImage(ids1.get(0)); @@ -787,8 +720,7 @@ public void testImportAndRenameImages() throws Exception { image1.addPairKeyValue(client, "Map", "ReplaceTest"); long fileId = image1.addFile(client, file); - if (!file.delete()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be deleted."); + removeFile(file); assertNotEquals(0L, fileId); List ids2 = dataset.importImage(client, imageFile.getAbsolutePath()); @@ -818,7 +750,7 @@ public void testImportAndRenameImages() throws Exception { image1.addTable(client, table); image2.addTable(client, table); - List ids3 = dataset.importAndReplaceImages(client, imageFile.getAbsolutePath()); + List ids3 = dataset.importAndReplaceImages(client, imageFile.getAbsolutePath(), DELETE); ImageWrapper image3 = client.getImage(ids3.get(0)); assertEquals(2, image3.getTags(client).size()); @@ -834,9 +766,90 @@ public void testImportAndRenameImages() throws Exception { assertEquals("This is\na test.", image3.getDescription()); client.delete(image3.getMapAnnotations(client).get(0)); + removeFile(imageFile); + + List images = dataset.getImages(client); + + client.delete(images); + List endImages = dataset.getImages(client); + client.delete(dataset); + client.delete(tag1); + client.delete(tag2); + client.delete(table); + client.deleteFile(fileId); + client.delete(roi); + client.delete(folder); + + assertEquals(1, images.size()); + assertTrue(endImages.isEmpty()); + } + + + @Test + public void testReplaceAndUnlinkImages() throws Exception { + String filename = "8bit-unsigned&pixelType=uint8&sizeZ=5&sizeC=5&sizeX=512&sizeY=512.fake"; + + DatasetWrapper dataset = new DatasetWrapper("Test Import & Replace", ""); + client.getProject(PROJECT1.id).addDataset(client, dataset); + + File imageFile = createFile(filename); + File file = createRandomFile("test_image.txt"); + + List ids1 = dataset.importImage(client, imageFile.getAbsolutePath()); + ImageWrapper image1 = client.getImage(ids1.get(0)); + + TagAnnotationWrapper tag1 = new TagAnnotationWrapper(client, "ReplaceTestTag1", "Copy annotations"); + image1.addTag(client, tag1); + image1.addPairKeyValue(client, "Map", "ReplaceTest"); + + long fileId = image1.addFile(client, file); + removeFile(file); + assertNotEquals(0L, fileId); + + List ids2 = dataset.importImage(client, imageFile.getAbsolutePath()); + ImageWrapper image2 = client.getImage(ids2.get(0)); + image2.setDescription("A test."); + image2.saveAndUpdate(client); + + TagAnnotationWrapper tag2 = new TagAnnotationWrapper(client, "ReplaceTestTag2", "Copy annotations"); + image2.addTag(client, tag2); + image2.addFileAnnotation(client, image1.getFileAnnotations(client).get(0)); + image2.addMapAnnotation(client, image1.getMapAnnotations(client).get(0)); + + final RectangleWrapper rectangle = new RectangleWrapper(30, 30, 20, 20); + ROIWrapper roi = new ROIWrapper(); + roi.setImage(image2); + roi.addShape(rectangle); + image2.saveROI(client, roi); + + FolderWrapper folder = new FolderWrapper(client, "ReplaceTestFolder"); + folder.setImage(image2); + folder.addROI(client, roi); + + TableWrapper table = new TableWrapper(1, "ReplaceTestTable"); + table.setColumn(0, "Name", String.class); + table.setRowCount(1); + table.addRow("Annotation"); + image1.addTable(client, table); + image2.addTable(client, table); + + List ids3 = dataset.importAndReplaceImages(client, imageFile.getAbsolutePath()); + ImageWrapper image3 = client.getImage(ids3.get(0)); + + assertEquals(2, image3.getTags(client).size()); + assertEquals(2, image3.getTables(client).size()); + assertEquals(3, image3.getFileAnnotations(client).size()); + assertEquals(1, image3.getMapAnnotations(client).size()); + assertEquals(1, image3.getROIs(client).size()); + assertEquals(1, image3.getFolders(client).size()); + assertEquals("ReplaceTestTag1", image3.getTags(client).get(0).getName()); + assertEquals("ReplaceTestTag2", image3.getTags(client).get(1).getName()); + assertEquals("ReplaceTest", image3.getValue(client, "Map")); + assertEquals("ReplaceTestTable", image3.getTables(client).get(0).getName()); + assertEquals("A test.", image3.getDescription()); - if (!imageFile.delete()) - System.err.println("\"" + imageFile.getCanonicalPath() + "\" could not be deleted."); + client.delete(image3.getMapAnnotations(client).get(0)); + removeFile(imageFile); List images = dataset.getImages(client); @@ -851,10 +864,123 @@ public void testImportAndRenameImages() throws Exception { client.deleteFile(fileId); client.delete(roi); client.delete(folder); + client.delete(image1); + client.delete(image2); assertEquals(1, images.size()); assertTrue(endImages.isEmpty()); } + @Test + public void testReplaceImagesFileset1() throws Exception { + String filename = "8bit-unsigned&pixelType=uint8&sizeZ=5&sizeC=5&series=2&sizeX=512&sizeY=512.fake"; + + DatasetWrapper dataset = new DatasetWrapper("Test Import & Replace", ""); + client.getProject(PROJECT1.id).addDataset(client, dataset); + + File imageFile = createFile(filename); + + List ids1 = dataset.importImage(client, imageFile.getAbsolutePath()); + List images1 = dataset.getImages(client); + + List ids2 = dataset.importAndReplaceImages(client, imageFile.getAbsolutePath(), DELETE); + List images2 = dataset.getImages(client); + + removeFile(imageFile); + + assertEquals(2, ids1.size()); + assertEquals(2, ids2.size()); + assertEquals(ids1.size(), images1.size()); + assertEquals(ids2.size(), images2.size()); + assertTrue(client.getImages(ids1.get(0), ids1.get(1)).isEmpty()); + + client.delete(images2); + List endImages = dataset.getImages(client); + client.delete(dataset); + + assertTrue(endImages.isEmpty()); + } + + + @Test + public void testReplaceImagesFileset2() throws Exception { + String filename = "8bit-unsigned&pixelType=uint8&sizeZ=5&sizeC=5&series=2&sizeX=512&sizeY=512.fake"; + + DatasetWrapper dataset = new DatasetWrapper("Test Import & Replace", ""); + client.getProject(PROJECT1.id).addDataset(client, dataset); + + File imageFile = createFile(filename); + + List ids1 = dataset.importImage(client, imageFile.getAbsolutePath()); + assertEquals(2, ids1.size()); + List images1 = dataset.getImages(client); + assertEquals(ids1.size(), images1.size()); + dataset.removeImage(client, images1.get(0)); + List fsImages = images1.get(0).getFilesetImages(client); + assertEquals(images1.size(), fsImages.size()); + assertTrue(ids1.contains(fsImages.get(0).getId())); + assertTrue(ids1.contains(fsImages.get(1).getId())); + + List ids2 = dataset.importAndReplaceImages(client, imageFile.getAbsolutePath(), DELETE); + assertEquals(2, ids2.size()); + List images2 = dataset.getImages(client); + assertEquals(ids2.size(), images2.size()); + + removeFile(imageFile); + + List images3 = client.getImages(ids1.get(0), ids1.get(1)); + assertEquals(2, images3.size()); + assertFalse(images2.get(0).isOrphaned(client)); + assertTrue(images3.get(0).isOrphaned(client)); + + client.delete(images1); + client.delete(images2); + List endImages = dataset.getImages(client); + client.delete(dataset); + + assertTrue(endImages.isEmpty()); + } + + + @Test + public void testReplaceImagesFileset3() throws Exception { + String filename = "8bit-unsigned&pixelType=uint8&sizeZ=5&sizeC=5&series=2&sizeX=512&sizeY=512.fake"; + + DatasetWrapper dataset = new DatasetWrapper("Test Import & Replace", ""); + client.getProject(PROJECT1.id).addDataset(client, dataset); + + File imageFile = createFile(filename); + + List ids1 = dataset.importImage(client, imageFile.getAbsolutePath()); + assertEquals(2, ids1.size()); + List images1 = dataset.getImages(client); + assertEquals(ids1.size(), images1.size()); + dataset.removeImage(client, images1.get(0)); + List fsImages = images1.get(0).getFilesetImages(client); + assertEquals(images1.size(), fsImages.size()); + assertTrue(ids1.contains(fsImages.get(0).getId())); + assertTrue(ids1.contains(fsImages.get(1).getId())); + + List ids2 = dataset.importAndReplaceImages(client, imageFile.getAbsolutePath(), DELETE_ORPHANED); + assertEquals(2, ids2.size()); + List images2 = dataset.getImages(client); + assertEquals(ids2.size(), images2.size()); + + removeFile(imageFile); + + assertEquals(2, ids1.size()); + assertEquals(2, ids2.size()); + assertEquals(ids1.size(), images1.size()); + assertEquals(ids2.size(), images2.size()); + assertTrue(client.getImages(ids1.get(0), ids1.get(1)).isEmpty()); + + client.delete(images2); + List endImages = dataset.getImages(client); + client.delete(dataset); + + assertTrue(endImages.isEmpty()); + } + + } diff --git a/src/test/java/fr/igred/omero/repository/ProjectTest.java b/src/test/java/fr/igred/omero/repository/ProjectTest.java index 625944d6..52911c05 100644 --- a/src/test/java/fr/igred/omero/repository/ProjectTest.java +++ b/src/test/java/fr/igred/omero/repository/ProjectTest.java @@ -24,12 +24,10 @@ import org.junit.Test; import java.io.File; -import java.io.FileOutputStream; -import java.io.PrintStream; -import java.nio.charset.StandardCharsets; -import java.security.SecureRandom; import java.util.List; +import static fr.igred.omero.repository.GenericRepositoryObjectWrapper.ReplacePolicy.DELETE; +import static fr.igred.omero.repository.GenericRepositoryObjectWrapper.ReplacePolicy.DELETE_ORPHANED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; @@ -296,20 +294,10 @@ public void testCopyAnnotations() throws Exception { ProjectWrapper project1 = client.getProject(PROJECT1.id); ProjectWrapper project2 = new ProjectWrapper(client, "CopyTest", "Copy annotations"); - File file = new File("." + File.separator + "test.txt"); - if (!file.createNewFile()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be created."); - - final byte[] array = new byte[2 * 262144 + 20]; - new SecureRandom().nextBytes(array); - String generatedString = new String(array, StandardCharsets.UTF_8); - try (PrintStream out = new PrintStream(new FileOutputStream(file), false, "UTF-8")) { - out.print(generatedString); - } + File file = createRandomFile("test_project.txt"); Long fileId = project1.addFile(client, file); - if (!file.delete()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be deleted."); + removeFile(file); assertNotEquals(0L, fileId.longValue()); TagAnnotationWrapper tag = new TagAnnotationWrapper(client, "CopyTestTag", "Copy annotations"); @@ -333,8 +321,8 @@ public void testCopyAnnotations() throws Exception { client.delete(tag); client.delete(table); List maps = project1.getMapAnnotations(client); - if(!maps.isEmpty()) - for(MapAnnotationWrapper map : maps) + if (!maps.isEmpty()) + for (MapAnnotationWrapper map : maps) client.delete(map); assertEquals(0, project2.getTags(client).size()); @@ -351,26 +339,16 @@ public void testCopyFileAnnotation() throws Exception { ProjectWrapper project1 = client.getProject(PROJECT1.id); ProjectWrapper project2 = new ProjectWrapper(client, "CopyTest", "Copy file annotation"); - File file = new File("." + File.separator + "test.txt"); - if (!file.createNewFile()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be created."); - - final byte[] array = new byte[2 * 262144 + 20]; - new SecureRandom().nextBytes(array); - String generatedString = new String(array, StandardCharsets.UTF_8); - try (PrintStream out = new PrintStream(new FileOutputStream(file), false, "UTF-8")) { - out.print(generatedString); - } + File file = createRandomFile("test_project.txt"); Long fileId = project1.addFile(client, file); - if (!file.delete()) - System.err.println("\"" + file.getCanonicalPath() + "\" could not be deleted."); + removeFile(file); assertNotEquals(0L, fileId.longValue()); List files = project1.getFileAnnotations(client); assertEquals(1, files.size()); - if(!files.isEmpty()) { + if (!files.isEmpty()) { project2.addFileAnnotation(client, files.get(0)); } assertEquals(1, project2.getFileAnnotations(client).size()); @@ -381,4 +359,90 @@ public void testCopyFileAnnotation() throws Exception { assertNotEquals(0L, fileId.longValue()); } + + @Test + public void testReplaceAndUnlinkFile() throws Exception { + ProjectWrapper project1 = new ProjectWrapper(client, "ReplaceTest1", "Replace file annotation"); + ProjectWrapper project2 = new ProjectWrapper(client, "ReplaceTest2", "Replace file annotation"); + + File file = createRandomFile("test_project.txt"); + + long fileId1 = project1.addFile(client, file); + assertEquals(1, project1.getFileAnnotations(client).size()); + project2.addFileAnnotation(client, project1.getFileAnnotations(client).get(0)); + long fileId2 = project1.addAndReplaceFile(client, file); + assertEquals(1, project1.getFileAnnotations(client).size()); + assertEquals(1, project2.getFileAnnotations(client).size()); + assertNotEquals(fileId1, fileId2); + + removeFile(file); + client.delete(project1); + client.delete(project2); + client.deleteFile(fileId1); + client.deleteFile(fileId2); + } + + + @Test + public void testReplaceAndDeleteFile() throws Exception { + ProjectWrapper project1 = new ProjectWrapper(client, "ReplaceTest1", "Replace file annotation"); + ProjectWrapper project2 = new ProjectWrapper(client, "ReplaceTest2", "Replace file annotation"); + + File file = createRandomFile("test_project.txt"); + + long fileId1 = project1.addFile(client, file); + assertEquals(1, project1.getFileAnnotations(client).size()); + project2.addFileAnnotation(client, project1.getFileAnnotations(client).get(0)); + long fileId2 = project1.addAndReplaceFile(client, file, DELETE); + assertEquals(1, project1.getFileAnnotations(client).size()); + assertEquals(0, project2.getFileAnnotations(client).size()); + assertNotEquals(fileId1, fileId2); + + removeFile(file); + client.delete(project1); + client.delete(project2); + client.deleteFile(fileId2); + } + + + @Test + public void testReplaceAndDeleteOrphanedFile1() throws Exception { + ProjectWrapper project1 = new ProjectWrapper(client, "ReplaceTest1", "Replace file annotation"); + ProjectWrapper project2 = new ProjectWrapper(client, "ReplaceTest2", "Replace file annotation"); + + File file = createRandomFile("test_project.txt"); + + long fileId1 = project1.addFile(client, file); + assertEquals(1, project1.getFileAnnotations(client).size()); + project2.addFileAnnotation(client, project1.getFileAnnotations(client).get(0)); + long fileId2 = project1.addAndReplaceFile(client, file, DELETE_ORPHANED); + assertEquals(1, project1.getFileAnnotations(client).size()); + assertEquals(1, project2.getFileAnnotations(client).size()); + assertNotEquals(fileId1, fileId2); + + removeFile(file); + client.delete(project1); + client.delete(project2); + client.deleteFile(fileId1); + client.deleteFile(fileId2); + } + + + @Test + public void testReplaceAndDeleteOrphanedFile2() throws Exception { + ProjectWrapper project1 = new ProjectWrapper(client, "ReplaceTest1", "Replace file annotation"); + + File file = createRandomFile("test_project.txt"); + + long fileId1 = project1.addFile(client, file); + assertEquals(1, project1.getFileAnnotations(client).size()); + long fileId2 = project1.addAndReplaceFile(client, file, DELETE_ORPHANED); + assertEquals(1, project1.getFileAnnotations(client).size()); + assertNotEquals(fileId1, fileId2); + + removeFile(file); + client.delete(project1); + client.deleteFile(fileId2); + } + } diff --git a/src/test/java/fr/igred/omero/repository/WellSampleTest.java b/src/test/java/fr/igred/omero/repository/WellSampleTest.java index e0ec70d2..276c3bec 100644 --- a/src/test/java/fr/igred/omero/repository/WellSampleTest.java +++ b/src/test/java/fr/igred/omero/repository/WellSampleTest.java @@ -20,6 +20,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; public class WellSampleTest extends UserTest { @@ -36,6 +37,7 @@ public void testGetImage() throws Exception { ImageWrapper image = sample.getImage(); + assertFalse(image.isOrphaned(client)); assertEquals(name, image.getName()); } diff --git a/src/test/java/fr/igred/omero/roi/ROITest.java b/src/test/java/fr/igred/omero/roi/ROITest.java index e499f369..f7ebb3d8 100644 --- a/src/test/java/fr/igred/omero/roi/ROITest.java +++ b/src/test/java/fr/igred/omero/roi/ROITest.java @@ -22,7 +22,6 @@ import java.awt.geom.Point2D; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import static org.junit.Assert.assertEquals;