1 package com.github.celldynamics.quimp.omero;
2
3 import java.io.Closeable;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.net.URISyntaxException;
9 import java.nio.ByteBuffer;
10 import java.nio.file.Path;
11 import java.nio.file.Paths;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Collection;
15 import java.util.Iterator;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Properties;
19 import java.util.concurrent.ExecutionException;
20
21 import org.apache.commons.io.FilenameUtils;
22 import org.scijava.Context;
23 import org.scijava.io.IOService;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import com.github.celldynamics.quimp.QuimpException;
28
29 import Glacier2.CannotCreateSessionException;
30 import Glacier2.PermissionDeniedException;
31 import edu.emory.mathcs.backport.java.util.Collections;
32 import loci.formats.in.DefaultMetadataOptions;
33 import loci.formats.in.MetadataLevel;
34 import net.imagej.Dataset;
35 import net.imagej.omero.DefaultOMEROSession;
36 import net.imagej.omero.OMEROLocation;
37 import net.imagej.omero.OMEROService;
38 import ome.formats.OMEROMetadataStoreClient;
39 import ome.formats.importer.ImportCandidates;
40 import ome.formats.importer.ImportConfig;
41 import ome.formats.importer.ImportLibrary;
42 import ome.formats.importer.OMEROWrapper;
43 import ome.formats.importer.cli.ErrorHandler;
44 import ome.formats.importer.cli.LoggingImportMonitor;
45 import omero.ServerError;
46 import omero.client;
47 import omero.api.IMetadataPrx;
48 import omero.api.RawFileStorePrx;
49 import omero.gateway.Gateway;
50 import omero.gateway.SecurityContext;
51 import omero.gateway.exception.DSAccessException;
52 import omero.gateway.exception.DSOutOfServiceException;
53 import omero.gateway.facility.BrowseFacility;
54 import omero.gateway.facility.DataManagerFacility;
55 import omero.gateway.model.DatasetData;
56 import omero.gateway.model.FileAnnotationData;
57 import omero.gateway.model.ImageData;
58 import omero.gateway.model.ProjectData;
59 import omero.model.Annotation;
60 import omero.model.ChecksumAlgorithm;
61 import omero.model.ChecksumAlgorithmI;
62 import omero.model.FileAnnotation;
63 import omero.model.FileAnnotationI;
64 import omero.model.Image;
65 import omero.model.ImageAnnotationLink;
66 import omero.model.ImageAnnotationLinkI;
67 import omero.model.OriginalFile;
68 import omero.model.OriginalFileI;
69 import omero.model.enums.ChecksumAlgorithmSHA1160;
70 import omero.sys.ParametersI;
71
72
73
74
75
76
77
78 public class OmeroBrowser implements Closeable {
79 private static final String NAMESPACE = "QCONF";
80 static final Logger LOGGER = LoggerFactory.getLogger(OmeroBrowser.class.getName());
81 static final int DEF_PORT = 4064;
82
83 private Gateway gateway = null;
84 private SecurityContext ctx;
85 private String user;
86 private String host;
87 private String pass;
88 private client client;
89 private DefaultOMEROSession ds;
90 OMEROService os;
91 Context context;
92 private int port;
93
94
95
96
97
98
99
100
101
102
103
104 public OmeroBrowser(String user, String pass, String host, int port) {
105 this.port = port;
106 this.host = host;
107 this.user = user;
108 this.pass = pass;
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 public void connect() throws DSOutOfServiceException, QuimpException, URISyntaxException,
125 ServerError, PermissionDeniedException, CannotCreateSessionException {
126 silentClose();
127 LOGGER.debug("Opening connection:" + user + ", " + pass + ", " + host);
128 if (user == null || user.isEmpty() || host == null || host.isEmpty() || pass == null
129 || pass.isEmpty()) {
130 throw new QuimpException("One of required fields is empty");
131 }
132 OMEROLocation credentials = new OMEROLocation(host, port, user, pass);
133 context = new Context();
134 os = context.getService(OMEROService.class);
135 ds = new DefaultOMEROSession(credentials, os);
136 client = ds.getClient();
137 gateway = ds.getGateway();
138 ctx = ds.getSecurityContext();
139 }
140
141
142
143
144
145
146 @Override
147 public void close() throws IOException {
148 silentClose();
149 }
150
151
152
153
154 public void silentClose() {
155 if (gateway != null) {
156 ds.close();
157 client.closeSession();
158 gateway.disconnect();
159 os.dispose();
160 context.dispose();
161 LOGGER.debug("Omero disconnected");
162 }
163 }
164
165
166
167
168
169
170
171
172
173 public List<ProjectData> listProjects()
174 throws DSOutOfServiceException, DSAccessException, ExecutionException {
175 BrowseFacility browse = gateway.getFacility(BrowseFacility.class);
176 return new ArrayList<ProjectData>(browse.getProjects(ctx));
177 }
178
179
180
181
182
183
184
185
186
187 public List<DatasetData> listDatasets()
188 throws DSOutOfServiceException, DSAccessException, ExecutionException {
189 BrowseFacility browse = gateway.getFacility(BrowseFacility.class);
190 return new ArrayList<DatasetData>(browse.getDatasets(ctx));
191 }
192
193
194
195
196
197
198
199
200
201
202 public Collection<ImageData> openDataset(DatasetData name)
203 throws ExecutionException, DSOutOfServiceException, DSAccessException {
204 BrowseFacility browse = gateway.getFacility(BrowseFacility.class);
205 List<Long> ida = new ArrayList<>();
206 ida.add(name.getId());
207 return browse.getImagesForDatasets(ctx, ida);
208
209 }
210
211
212
213
214
215
216
217
218
219
220 public DatasetData findDataset(String name)
221 throws DSOutOfServiceException, DSAccessException, ExecutionException {
222 for (DatasetData ds : listDatasets()) {
223 if (ds.getName().equals(name)) {
224 LOGGER.debug("Found dataset of name " + name + " (" + ds.toString() + ")");
225 return ds;
226 }
227 }
228 return null;
229 }
230
231
232
233
234
235
236
237
238
239
240 public DatasetData findDataset(Long id)
241 throws DSOutOfServiceException, DSAccessException, ExecutionException {
242 for (DatasetData ds : listDatasets()) {
243 if (ds.getId() == id) {
244 LOGGER.debug("Found dataset of id " + id + " (" + ds.toString() + ")");
245 return ds;
246 }
247 }
248 return null;
249 }
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269 public ImageData findImage(String imageName, DatasetData name, boolean allowDuplicates)
270 throws ExecutionException, DSOutOfServiceException, DSAccessException, QuimpException {
271 ArrayList<ImageData> imgs = new ArrayList<>();
272 for (ImageData im : openDataset(name)) {
273 if (im.getName().equals(imageName)) {
274 LOGGER.debug("Found image of name " + name + " (" + im.toString() + "), inserted: "
275 + im.getInserted());
276 imgs.add(im);
277 }
278 }
279 if (imgs.size() > 1 && allowDuplicates == false) {
280 throw new QuimpException(
281 "There are at least two images with name " + imageName + " in dataset");
282 }
283 if (imgs.size() == 0) {
284 return null;
285 }
286 if (imgs.size() == 1) {
287 return imgs.get(0);
288 } else {
289 Long now = System.currentTimeMillis();
290 ArrayList<Long> deltas = new ArrayList<>();
291 for (ImageData im : imgs) {
292 Long timeFile = im.getInserted().getTime();
293 deltas.add(now - timeFile);
294 }
295 int closestInd = deltas.indexOf(Collections.min(deltas));
296 return imgs.get(closestInd);
297 }
298
299 }
300
301
302
303
304
305
306
307
308
309
310
311 public ImageData findImage(Long imageId, DatasetData name)
312 throws ExecutionException, DSOutOfServiceException, DSAccessException {
313 for (ImageData im : openDataset(name)) {
314 if (im.getId() == imageId) {
315 LOGGER.debug("Found image of id " + imageId + " (" + imageId.toString() + ")");
316 return im;
317 }
318 }
319 return null;
320
321 }
322
323
324
325
326
327
328
329
330 public void upload(String[] pathsToImages, DatasetData name) throws Exception {
331 LOGGER.info("Trying to upload: " + Arrays.toString(pathsToImages));
332 ImportConfig config = new ome.formats.importer.ImportConfig();
333 config.email.set("");
334 config.sendFiles.set(true);
335 config.sendReport.set(false);
336 config.contOnError.set(false);
337 config.debug.set(true);
338
339 config.hostname.set(host);
340 config.port.set(port);
341 config.username.set(user);
342 config.password.set(pass);
343 config.target.set("omero.model.Dataset:" + name.getId());
344
345 OMEROMetadataStoreClient store;
346 store = config.createStore();
347 store.logVersionInfo(config.getIniVersionNumber());
348 OMEROWrapper reader = new OMEROWrapper(config);
349 ImportLibrary library = new ImportLibrary(store, reader);
350
351 ErrorHandler handler = new ErrorHandler(config);
352 library.addObserver(new LoggingImportMonitor());
353
354 ImportCandidates candidates = new ImportCandidates(reader, pathsToImages, handler);
355 reader.setMetadataOptions(new DefaultMetadataOptions(MetadataLevel.ALL));
356 library.importCandidates(config, candidates);
357
358 store.logout();
359 LOGGER.info("Image uploaded");
360
361 }
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378 public void upload(String imageName, String pathToAttach, DatasetData name)
379 throws IOException, DSOutOfServiceException, DSAccessException, ServerError,
380 ExecutionException, QuimpException {
381 LOGGER.info("Trying to upload attachement: " + pathToAttach + " to " + imageName);
382
383 File file = new File(pathToAttach);
384 String name1 = Paths.get(pathToAttach).getFileName().toString();
385 String absolutePath = file.getAbsolutePath();
386 String path = absolutePath.substring(0, absolutePath.length() - name1.length());
387
388
389 OriginalFile originalFile = new OriginalFileI();
390 originalFile.setName(omero.rtypes.rstring(name1));
391 originalFile.setPath(omero.rtypes.rstring(path));
392 originalFile.setSize(omero.rtypes.rlong(file.length()));
393 final ChecksumAlgorithm checksumAlgorithm = new ChecksumAlgorithmI();
394 checksumAlgorithm.setValue(omero.rtypes.rstring(ChecksumAlgorithmSHA1160.value));
395 originalFile.setHasher(checksumAlgorithm);
396 originalFile.setMimetype(omero.rtypes.rstring("application/octet-stream"));
397
398 DataManagerFacility dm = gateway.getFacility(DataManagerFacility.class);
399 originalFile = (OriginalFile) dm.saveAndReturnObject(ctx, originalFile);
400
401
402 RawFileStorePrx rawFileStore = gateway.getRawFileService(ctx);
403
404 long inc = file.length();
405 long pos = 0;
406 int rlen;
407 byte[] buf = new byte[(int) inc];
408 ByteBuffer bbuf;
409
410 try (FileInputStream stream = new FileInputStream(file)) {
411 rawFileStore.setFileId(originalFile.getId().getValue());
412 while ((rlen = stream.read(buf)) > 0) {
413 rawFileStore.write(buf, pos, rlen);
414 pos += rlen;
415 bbuf = ByteBuffer.wrap(buf);
416 bbuf.limit(rlen);
417 }
418 originalFile = rawFileStore.save();
419 } finally {
420 rawFileStore.close();
421 }
422
423
424
425 FileAnnotation fa = new FileAnnotationI();
426 fa.setFile(originalFile);
427
428 fa.setDescription(omero.rtypes.rstring("PointsModel"));
429
430 fa.setNs(omero.rtypes.rstring(NAMESPACE));
431
432
433 fa = (FileAnnotation) dm.saveAndReturnObject(ctx, fa);
434
435
436 ImageAnnotationLink link = new ImageAnnotationLinkI();
437 link.setChild(fa);
438 ImageData imageData = findImage(imageName, name, true);
439 link.setParent(imageData.asImage());
440
441 link = (ImageAnnotationLink) dm.saveAndReturnObject(ctx, link);
442
443 LOGGER.info("Attachement uploaded");
444
445 }
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461 public void download(ImageData image, Path path)
462 throws DSOutOfServiceException, ServerError, DSAccessException, ExecutionException,
463 IOException, URISyntaxException, PermissionDeniedException, CannotCreateSessionException {
464
465 if (path.toFile().isFile()) {
466 throw new IllegalArgumentException("Path must point to folder");
467 }
468
469 Dataset img = os.downloadImage(client, image.getId());
470 IOService io = context.getService(IOService.class);
471 Path imageFile = path.resolve(image.getName());
472 io.save(img, imageFile.toString());
473 long[] dim = new long[img.numDimensions()];
474 img.dimensions(dim);
475 LOGGER.info("Saved: " + imageFile.toString() + " : " + img.toString() + " dim: "
476 + Arrays.toString(dim));
477
478 long userId = gateway.getLoggedInUser().getId();
479 List<String> nsToInclude = new ArrayList<String>();
480 nsToInclude.add(NAMESPACE);
481 List<String> nsToExclude = new ArrayList<String>();
482 ParametersI param = new ParametersI();
483 param.exp(omero.rtypes.rlong(userId));
484 IMetadataPrx proxy = gateway.getMetadataService(ctx);
485 List<Long> ids = new ArrayList<>();
486 ids.add(image.getId());
487 Map<Long, List<Annotation>> annotations =
488 proxy.loadSpecifiedAnnotationsLinkedTo(FileAnnotation.class.getName(), nsToInclude,
489 nsToExclude, Image.class.getName(), ids, param);
490 LOGGER.debug("Length: " + annotations.size());
491
492
493
494
495
496
497
498 if (annotations.get(image.getId()) != null) {
499 Iterator<Annotation> j = annotations.get(image.getId()).iterator();
500 Annotation annotation;
501 FileAnnotationData fa;
502 RawFileStorePrx store = gateway.getRawFileService(ctx);
503 File qconfFile =
504 path.resolve(FilenameUtils.removeExtension(image.getName()) + ".QCONF").toFile();
505 int index = 0;
506
507 int inc;
508 try (FileOutputStream stream = new FileOutputStream(qconfFile)) {
509 while (j.hasNext()) {
510 annotation = j.next();
511 if (annotation instanceof FileAnnotation && index == 0) {
512 fa = new FileAnnotationData((FileAnnotation) annotation);
513
514
515 OriginalFile originalFile = new OriginalFileI();
516 originalFile.setName(omero.rtypes.rstring(qconfFile.getName()));
517 originalFile.setPath(omero.rtypes.rstring(qconfFile.getParent()));
518 originalFile.setSize(omero.rtypes.rlong(fa.getFileSize()));
519 final ChecksumAlgorithm checksumAlgorithm = new ChecksumAlgorithmI();
520 checksumAlgorithm.setValue(omero.rtypes.rstring(ChecksumAlgorithmSHA1160.value));
521 originalFile.setHasher(checksumAlgorithm);
522 originalFile.setMimetype(omero.rtypes.rstring("application/octet-stream"));
523
524 DataManagerFacility dm = gateway.getFacility(DataManagerFacility.class);
525 originalFile = (OriginalFile) dm.saveAndReturnObject(ctx, originalFile);
526
527 store.setFileId(fa.getFileID());
528 int offset = 0;
529 inc = (int) fa.getFileSize();
530 long size = originalFile.getSize().getValue();
531 try {
532 for (offset = 0; (offset + inc) < size;) {
533 stream.write(store.read(offset, inc));
534 offset += inc;
535 }
536 } finally {
537 stream.write(store.read(offset, (int) (size - offset)));
538 LOGGER.info("Saved: " + qconfFile.toString() + " from image " + image.getId());
539 }
540 index++;
541 }
542 }
543 } finally {
544 store.close();
545 }
546 } else {
547 LOGGER.warn("There is no QCONF file attached to image [ " + image.getId() + "]");
548 }
549 }
550
551
552
553
554
555
556 public static void main(String[] args) {
557 String user;
558 String pass;
559 String host;
560 Properties prop = new Properties();
561 try (FileInputStream input = new FileInputStream(
562 Paths.get(System.getProperty("user.home"), "omero.properties").toFile())) {
563 prop.load(input);
564 user = prop.getProperty("user");
565 pass = prop.getProperty("pass");
566 host = prop.getProperty("host");
567 } catch (IOException ex) {
568 ex.printStackTrace();
569 return;
570 }
571
572 try (OmeroBrowsermero/OmeroBrowser.html#OmeroBrowser">OmeroBrowser client = new OmeroBrowser(user, pass, host, DEF_PORT)) {
573 client.connect();
574 LOGGER.debug("Projects:");
575 client.listDatasets().stream().forEach(x -> LOGGER.debug("dataset " + x.getName()));
576
577 DatasetData ds = client.findDataset("Q");
578
579 client.openDataset(ds).stream()
580 .forEach(x -> LOGGER.debug("image: " + x.getName() + ": " + x.getId()));
581
582
583
584
585
586 client.download(client.findImage(194021L, ds), Paths.get("./").toAbsolutePath());
587
588
589
590 } catch (Exception e) {
591
592 e.printStackTrace();
593 }
594
595
596
597
598 }
599
600 }