Skip to content

Commit

Permalink
Solve #24 and #25 (#26)
Browse files Browse the repository at this point in the history
* Bump version
* Add methods to retrieve/add/copy annotations from/to a repository object
* Add method to retrieve images from project, dataset and image name (see #24)
* Add method to import file and replace images in dataset (see #25)
* Add tests
* Fix table name missing from getTable
* Fix default namespace for MapAnnotations
* Fix redundant annotations being copied
  • Loading branch information
ppouchin authored May 4, 2022
1 parent fcdd038 commit 5b36e30
Show file tree
Hide file tree
Showing 9 changed files with 416 additions and 11 deletions.
2 changes: 1 addition & 1 deletion .omeroci/test-data
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ omero login testUser@localhost -w password -g testGroup

# create a simple project/dataset/image hierarchy
PROJECT1=$(omero obj new Project name=TestProject description=description)
PROJECT2=$(omero obj new Project name=TestProject)
PROJECT2=$(omero obj new Project name=TestProject2)

DATASET1=$(omero obj new Dataset name=TestDataset description=description)
DATASET2=$(omero obj new Dataset name=TestDatasetImport)
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<groupId>fr.igred</groupId>
<artifactId>simple-omero-client</artifactId>
<version>5.9.0</version>
<version>5.9.1</version>
<packaging>jar</packaging>

<name>Simple OMERO Client</name>
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/fr/igred/omero/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,33 @@ public List<ImageWrapper> getImages(String name) throws ServiceException, Access
}


/**
* Gets all images with the name specified inside projects and datasets with the given names.
*
* @param projectName Expected project name.
* @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<ImageWrapper> getImages(String projectName, String datasetName, String imageName)
throws ServiceException, AccessException, ExecutionException {
List<ImageWrapper> images = new ArrayList<>();
List<ProjectWrapper> projects = getProjects(projectName);
for (ProjectWrapper project : projects) {
List<DatasetWrapper> datasets = project.getDatasets(datasetName);
for (DatasetWrapper dataset : datasets) {
images.addAll(dataset.getImages(this, imageName));
}
}
return images;
}


/**
* Gets all images with a certain motif in their name from OMERO.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,14 @@ public boolean isMovieFile() {
return data.isMovieFile();
}


/**
* Gets the FileAnnotationData contained.
*
* @return the {@link FileAnnotationData} contained.
*/
public FileAnnotationData asFileAnnotationData() {
return data;
}

}
53 changes: 50 additions & 3 deletions src/main/java/fr/igred/omero/repository/DatasetWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import fr.igred.omero.exception.AccessException;
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;
Expand Down Expand Up @@ -69,6 +70,8 @@ public class DatasetWrapper extends GenericRepositoryObjectWrapper<DatasetData>

public static final String ANNOTATION_LINK = "DatasetAnnotationLink";

private static final Long[] LONGS = new Long[0];


/**
* Constructor of the DatasetWrapper class
Expand Down Expand Up @@ -410,7 +413,7 @@ public void removeImage(Client client, ImageWrapper image)
* Imports all images candidates in the paths to the dataset in OMERO.
*
* @param client The client handling the connection.
* @param paths Paths to the image on your computer.
* @param paths Paths to the image files on the computer.
*
* @return If the import did not exit because of an error.
*
Expand Down Expand Up @@ -453,10 +456,10 @@ public boolean importImages(Client client, String... paths)


/**
* Imports one image candidate in the paths to the dataset in OMERO.
* Imports one image file to the dataset in OMERO.
*
* @param client The client handling the connection.
* @param path Path to the image on your computer.
* @param path Path to the image file on the computer.
*
* @return The list of IDs of the newly imported images.
*
Expand Down Expand Up @@ -511,6 +514,50 @@ public List<Long> importImage(Client client, String path)
}


/**
* 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).
*
* @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<Long> importAndReplaceImages(Client client, String path)
throws ServiceException, AccessException, OMEROServerError, ExecutionException, InterruptedException {
List<Long> ids = importImage(client, path);
Long[] newIds = ids.toArray(LONGS);

List<ImageWrapper> newImages = client.getImages(newIds);
for (ImageWrapper image : newImages) {
List<ImageWrapper> oldImages = getImages(client, image.getName());
oldImages.removeIf(i -> ids.contains(i.getId()));
ArrayList<String> descriptions = new ArrayList<>(oldImages.size() + 1);
descriptions.add(image.getDescription());
for (ImageWrapper oldImage : oldImages) {
descriptions.add(oldImage.getDescription());
image.copyAnnotations(client, oldImage);
List<ROIWrapper> rois = oldImage.getROIs(client);
for (ROIWrapper roi : rois) {
roi.setImage(image);
image.saveROI(client, roi);
}
client.delete(oldImage);
}
descriptions.removeIf(s -> s == null || s.trim().isEmpty());
image.setDescription(String.join("\n", descriptions));
image.saveAndUpdate(client);
}
return ids;
}


/**
* Refreshes the wrapped dataset.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import fr.igred.omero.exception.AccessException;
import fr.igred.omero.exception.OMEROServerError;
import fr.igred.omero.exception.ServiceException;
import omero.constants.metadata.NSCLIENTMAPANNOTATION;
import omero.gateway.exception.DSAccessException;
import omero.gateway.exception.DSOutOfServiceException;
import omero.gateway.model.AnnotationData;
Expand Down Expand Up @@ -204,11 +205,11 @@ public void addTags(Client client, Long... ids)


/**
* Gets all tag linked to an object in OMERO, if possible.
* Gets all tags linked to an object in OMERO, if possible.
*
* @param client The client handling the connection.
*
* @return Collection of TagAnnotationWrapper each containing a tag linked to the object.
* @return List of TagAnnotationWrappers each containing a tag linked to the object.
*
* @throws ServiceException Cannot connect to OMERO.
* @throws AccessException Cannot access data.
Expand All @@ -234,6 +235,37 @@ public List<TagAnnotationWrapper> getTags(Client client)
}


/**
* Gets all map annotations linked to an object in OMERO, if possible.
*
* @param client The client handling the connection.
*
* @return List of MapAnnotationWrappers.
*
* @throws ServiceException Cannot connect to OMERO.
* @throws AccessException Cannot access data.
* @throws ExecutionException A Facility can't be retrieved or instantiated.
*/
public List<MapAnnotationWrapper> getMapAnnotations(Client client)
throws ServiceException, AccessException, ExecutionException {
List<Class<? extends AnnotationData>> types = Collections.singletonList(MapAnnotationData.class);

List<AnnotationData> annotations = new ArrayList<>(0);
try {
annotations = client.getMetadata().getAnnotations(client.getCtx(), data, types, null);
} catch (DSOutOfServiceException | DSAccessException e) {
handleServiceOrAccess(e, "Cannot get tags for " + this);
}

return annotations.stream()
.filter(MapAnnotationData.class::isInstance)
.map(MapAnnotationData.class::cast)
.map(MapAnnotationWrapper::new)
.sorted(Comparator.comparing(MapAnnotationWrapper::getId))
.collect(Collectors.toList());
}


/**
* Adds a single Key-Value pair to the object.
*
Expand All @@ -247,8 +279,10 @@ public List<TagAnnotationWrapper> getTags(Client client)
*/
public void addPairKeyValue(Client client, String key, String value)
throws ServiceException, AccessException, ExecutionException {
List<NamedValue> kv = Collections.singletonList(new NamedValue(key, value));
addMapAnnotation(client, new MapAnnotationWrapper(kv));
List<NamedValue> kv = Collections.singletonList(new NamedValue(key, value));
MapAnnotationWrapper pkv = new MapAnnotationWrapper(kv);
pkv.setNameSpace(NSCLIENTMAPANNOTATION.value);
addMapAnnotation(client, pkv);
}


Expand Down Expand Up @@ -377,12 +411,20 @@ public void addTable(Client client, TableWrapper table)
public TableWrapper getTable(Client client, Long fileId)
throws ServiceException, AccessException, ExecutionException {
TableData table = null;
String name = null;
try {
table = client.getTablesFacility().getTable(client.getCtx(), fileId);
name = client.getTablesFacility()
.getAvailableTables(client.getCtx(), data)
.stream().filter(t -> t.getFileID() == fileId)
.map(FileAnnotationData::getDescription)
.findFirst().orElse(null);
} catch (DSOutOfServiceException | DSAccessException e) {
handleServiceOrAccess(e, "Cannot get table from " + this);
}
return new TableWrapper(Objects.requireNonNull(table));
TableWrapper result = new TableWrapper(Objects.requireNonNull(table));
result.setName(name);
return result;
}


Expand Down Expand Up @@ -438,6 +480,26 @@ public long addFile(Client client, File file) throws ExecutionException, Interru
}


/**
* Links a file annotation to the object
*
* @param client The client handling the connection.
* @param annotation FileAnnotationWrapper to link.
*
* @throws ServiceException Cannot connect to OMERO.
* @throws AccessException Cannot access data.
* @throws ExecutionException A Facility can't be retrieved or instantiated.
*/
public void addFileAnnotation(Client client, FileAnnotationWrapper annotation)
throws AccessException, ServiceException, ExecutionException {
try {
client.getDm().attachAnnotation(client.getCtx(), annotation.asFileAnnotationData(), this.data);
} catch (DSOutOfServiceException | DSAccessException e) {
handleServiceOrAccess(e, "Cannot link file annotation to " + this);
}
}


/**
* Returns the file annotations
*
Expand Down Expand Up @@ -509,4 +571,54 @@ protected void removeLink(Client client, String linkType, long childId)
}


/**
* Retrieves annotations linked to the object.
*
* @param client The client handling the connection.
*
* @return A list of annotations, as AnnotationData.
*
* @throws ServiceException Cannot connect to OMERO.
* @throws AccessException Cannot access data.
* @throws ExecutionException A Facility can't be retrieved or instantiated.
*/
private List<AnnotationData> getAnnotations(Client client)
throws AccessException, ServiceException, ExecutionException {
List<AnnotationData> annotations = new ArrayList<>(0);
try {
annotations = client.getMetadata().getAnnotations(client.getCtx(), data);
} catch (DSOutOfServiceException | DSAccessException e) {
handleServiceOrAccess(e, "Cannot get annotations from " + this);
}
return annotations;
}


/**
* Copies annotations from some other object to this one
*
* @param client The client handling the connection.
* @param object Other repository object to copy annotations from.
*
* @throws ServiceException Cannot connect to OMERO.
* @throws AccessException Cannot access data.
* @throws ExecutionException A Facility can't be retrieved or instantiated.
*/
public void copyAnnotations(Client client, GenericRepositoryObjectWrapper<?> object)
throws AccessException, ServiceException, ExecutionException {
List<AnnotationData> newAnnotations = object.getAnnotations(client);
List<AnnotationData> oldAnnotations = this.getAnnotations(client);
for (AnnotationData annotation : oldAnnotations) {
newAnnotations.removeIf(a -> a.getId() == annotation.getId());
}
try {
for (AnnotationData annotation : newAnnotations) {
client.getDm().attachAnnotation(client.getCtx(), annotation, this.data);
}
} catch (DSOutOfServiceException | DSAccessException e) {
handleServiceOrAccess(e, "Cannot link annotations to " + this);
}
}


}
9 changes: 8 additions & 1 deletion src/test/java/fr/igred/omero/ClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public void testGetProjectByName() throws Exception {
differences++;
}

assertEquals(2, projects.size());
assertEquals(1, projects.size());
assertEquals(0, differences);
}

Expand Down Expand Up @@ -175,6 +175,13 @@ public void testGetImagesKeyValue() throws Exception {
}


@Test
public void testGetImagesFromNames() throws Exception {
List<ImageWrapper> images = client.getImages(PROJECT1.name, DATASET1.name, IMAGE1.name);
assertEquals(2, images.size());
}


@Test
public void testGetImagesCond() throws Exception {
String key = "testKey2";
Expand Down
Loading

0 comments on commit 5b36e30

Please sign in to comment.