/* * Copyright (C) 2009-2014 University of Dundee & Open Microscopy Environment. * All rights reserved. * * Use is subject to license terms supplied in LICENSE.txt */ package ome.formats.importer.cli; import gnu.getopt.Getopt; import gnu.getopt.LongOpt; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import loci.formats.in.DefaultMetadataOptions; import loci.formats.in.MetadataLevel; import loci.formats.meta.MetadataStore; import ome.formats.OMEROMetadataStoreClient; import ome.formats.importer.ImportCandidates; import ome.formats.importer.ImportConfig; import ome.formats.importer.ImportContainer; import ome.formats.importer.ImportEvent; import ome.formats.importer.ImportLibrary; import ome.formats.importer.OMEROWrapper; import ome.formats.importer.exclusions.AbstractFileExclusion; import ome.formats.importer.exclusions.FileExclusion; import ome.formats.importer.transfers.AbstractFileTransfer; import ome.formats.importer.transfers.CleanupFailure; import ome.formats.importer.transfers.FileTransfer; import ome.formats.importer.transfers.UploadFileTransfer; import omero.api.ServiceFactoryPrx; import omero.api.ServiceInterfacePrx; import omero.cmd.HandlePrx; import omero.cmd.Response; import omero.grid.ImportProcessPrx; import omero.grid.ImportProcessPrxHelper; import omero.model.Annotation; import omero.model.CommentAnnotationI; import org.apache.commons.lang.time.StopWatch; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The base entry point for the CLI version of the OMERO importer. * * @author Chris Allan <callan@glencoesoftware.com> * @author Josh Moore josh at glencoesoftware.com */ public class CommandLineImporter { public static final int DEFAULT_WAIT = -1; /** Logger for this class. */ private static Logger log = LoggerFactory.getLogger(CommandLineImporter.class); /** StopWatch instance **/ private final StopWatch sw = new StopWatch(); /** Name that will be used for usage() */ private static final String APP_NAME = "importer-cli"; /** Configuration used by all components */ public final ImportConfig config; /** {@link FileTransfer} mechanism to be used for uploading */ public final FileTransfer transfer; /** {@link FileExclusion} mechanisms for skipping candidates */ public final List<FileExclusion> exclusions = new ArrayList<FileExclusion>(); /** Base importer library, this is what we actually use to import. */ public final ImportLibrary library; /** ErrorHandler which is also responsible for uploading files */ public final ErrorHandler handler; /** Bio-Formats reader wrapper customized for OMERO. */ private final OMEROWrapper reader; /** Bio-Formats {@link MetadataStore} implementation for OMERO. */ private final OMEROMetadataStoreClient store; /** Candidates for import */ private final ImportCandidates candidates; /** If true, then only a report on used files will be produced */ private final boolean getUsedFiles; /** * Legacy constructor which uses a {@link UploadFileTransfer}. * @param config the import configuration * @param paths files or directories to search * @param getUsedFiles if only getting a list of used files * @throws Exception if the import could not be set up */ public CommandLineImporter(final ImportConfig config, String[] paths, boolean getUsedFiles) throws Exception { this(config, paths, getUsedFiles, new UploadFileTransfer(), DEFAULT_WAIT); } /** * Legacy constructor without any file exclusions. * @param config the import configuration * @param paths files or directories to search * @param getUsedFiles if only getting a list of used files * @param transfer how files are to be transferred to the server * @param minutesToWait for how many minutes to wait for an import (negative for indefinitely) * @throws Exception if the import could not be set up */ public CommandLineImporter(final ImportConfig config, String[] paths, boolean getUsedFiles, FileTransfer transfer, int minutesToWait) throws Exception { this(config, paths, getUsedFiles, new UploadFileTransfer(), null, DEFAULT_WAIT); } /** * Main entry class for the application. * @param config the import configuration * @param paths files or directories to search * @param getUsedFiles if only getting a list of used files * @param transfer how files are to be transferred to the server * @param exclusions mechanisms to be used for skipping candidates * @param minutesToWait for how many minutes to wait for an import (negative for indefinitely) * @throws Exception if the import could not be set up */ public CommandLineImporter(final ImportConfig config, String[] paths, boolean getUsedFiles, FileTransfer transfer, List<FileExclusion> exclusions, int minutesToWait) throws Exception { this.config = config; config.loadAll(); this.getUsedFiles = getUsedFiles; this.reader = new OMEROWrapper(config); this.handler = new ErrorHandler(config); this.transfer = transfer; if (exclusions != null) { this.exclusions.addAll(exclusions); } candidates = new ImportCandidates(reader, paths, handler); if (paths == null || paths.length == 0 || getUsedFiles) { store = null; library = null; } else { // Ensure that we have all of our required login arguments if (!config.canLogin()) { // config.requestFromUser(); // stdin if anything missing. usage(); // EXITS TODO this should check for a "quiet" flag } if (config.checkUpgrade.get()) { config.isUpgradeNeeded(); } else { log.debug("UpgradeCheck disabled."); } store = config.createStore(); store.logVersionInfo(config.getIniVersionNumber()); reader.setMetadataOptions( new DefaultMetadataOptions(MetadataLevel.ALL)); library = new ImportLibrary(store, reader, transfer, exclusions, minutesToWait); } Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { cleanup(); } }); } /** * Look for all {@link ImportProcessPrx} in the current session and close * them if they return a non-null {@link Response} (i.e. they are done). * @param config the import configuration * @return how many import processes could not be accessed * @throws Exception in the event of error */ public static int closeCompleted(ImportConfig config) throws Exception { config.loadAll(); OMEROMetadataStoreClient client = config.createStore(); ImportCloser closer = new ImportCloser(client); closer.closeCompleted(); log.info("{} service(s) processed", closer.getProcessed()); return closer.getErrors(); } /** * Look for all {@link ImportProcessPrx} in the current session and close * them if they return a non-null {@link Response} (i.e. they are done). * @param config the import configuration * @return exit code, {@code 0} for success * @throws Exception in the event of error */ public static int waitCompleted(ImportConfig config) throws Exception { long wait = 5000L; config.loadAll(); OMEROMetadataStoreClient client = config.createStore(); while (true) { ImportCloser closer = new ImportCloser(client); closer.closeCompleted(); if (closer.getProcessed() == 0) { // In this case, there's nothing to do. Exit successfully. return 0; } int closed = closer.getClosed(); int open = closer.getProcessed() - closed; int errs = closer.getErrors(); if (errs > 0) { log.warn("{} open. {} closed. {} errors", open, closed, errs); } else { log.info("{} open. {} closed.", open, closed); } try { log.debug("Sleeping {} ms", wait); Thread.sleep(wait); } catch (Exception e) { // ignore } } } public int start() { boolean successful = true; if (getUsedFiles) { try { candidates.print(); return 0; } catch (Throwable t) { log.error("Error retrieving used files.", t); return 1; } } else if (candidates.size() < 1) { if (handler.errorCount() > 0) { System.err.println("No imports due to errors!"); report(); } else { System.err.println("No imports found"); try { cleanup(); // #5426 Preventing close exceptions. } finally { usage(); } } } else { sw.start(); library.addObserver(new LoggingImportMonitor()); // error handler has been configured in constructor from main args library.addObserver(this.handler); successful = library.importCandidates(config, candidates); try { List<String> paths = new ArrayList<String>(); for (ImportContainer ic : candidates.getContainers()) { paths.addAll(Arrays.asList(ic.getUsedFiles())); } // No exceptions are thrown from importCandidates and therefore // we must manually check for the number of errors. If there // are **ANY** then we refuse to post-process these paths, // which primarily only means that MoveFileTransfer will not // get a chance to delete the files. transfer.afterTransfer(handler.errorCount(), paths); } catch (CleanupFailure e) { log.error("Failed to cleanup {} files", e.getFailedFiles() .size()); return 3; } finally { sw.stop(); report(); } } return successful ? 0 : 2; } void report() { boolean report = config.sendReport.get(); boolean files = config.sendFiles.get(); boolean logs = config.sendLogFile.get(); if (report) { handler.update(null, new ImportEvent.DEBUG_SEND(files, logs)); } library.notifyObservers(new ImportEvent.IMPORT_SUMMARY(sw.getTime(), handler.errorCount())); } /** * Cleans up after a successful or unsuccessful image import. This method * only does the minimum required cleanup, so that it can be called * during shutdown. */ public void cleanup() { if (store != null) { store.logout(); } } /** * Prints usage to STDERR and exits with return code 1. */ public static void usage() { System.err.println(String.format("\n" + " Usage: %s [OPTION]... [path [path ...]]... \n" + " or: %s [OPTION]... - \n" + "\n" + "Import any number of files into an OMERO instance.\n" + "If \"-\" is the only path, a list of files or directories \n" + "is read from standard in. Directories will be searched for \n" + "all valid imports.\n" + "\n" + "Session arguments:\n" + " Mandatory arguments for creating a session are 1- either the OMERO server hostname,\n" + "username and password or 2- the OMERO server hostname and a valid session key.\n" + " -s SERVER\tOMERO server hostname\n" + " -u USER\tOMERO username\n" + " -w PASSWORD\tOMERO password\n" + " -k KEY\tOMERO session key (UUID of an active session)\n" + " -p PORT\tOMERO server port (default: 4064)\n" + "\n" + "Naming arguments:\n" + "All naming arguments are optional\n" + " -n NAME\t\t\t\tImage or plate name to use\n" + " -x DESCRIPTION\t\t\tImage or plate description to use\n" + " --name NAME\t\t\t\tImage or plate name to use\n" + " --description DESCRIPTION\t\tImage or plate description to use\n" + "\n" + "Optional arguments:\n" + " -h\t\t\t\t\tDisplay this help and exit\n" + " -f\t\t\t\t\tDisplay the used files and exit\n" + " -c\t\t\t\t\tContinue importing after errors\n" + " -l READER_FILE\t\t\tUse the list of readers rather than the default\n" + " -d DATASET_ID\t\t\t\tOMERO dataset ID to import image into\n" + " -r SCREEN_ID\t\t\t\tOMERO screen ID to import plate into\n" + " -T TARGET\t\t\t\ttarget for imports\n" + " --report\t\t\t\tReport errors to the OME team\n" + " --upload\t\t\t\tUpload broken files and log file (if any) with report. Required --report\n" + " --logs\t\t\t\tUpload log file (if any) with report. Required --report\n" + " --email EMAIL\t\t\t\tEmail for reported errors. Required --report\n" + " --debug LEVEL\t\t\t\tTurn debug logging on (optional level)\n" + " --annotation-ns ANNOTATION_NS\t\tNamespace to use for subsequent annotation\n" + " --annotation-text ANNOTATION_TEXT\tContent for a text annotation (requires namespace)\n" + " --annotation-link ANNOTATION_LINK\tComment annotation ID to link all images to\n" + "\n" + "Examples:\n" + "\n" + " $ %s -s localhost -u user -w password -d 50 foo.tiff\n" + " $ %s -s localhost -u user -w password -d Dataset:50 foo.tiff\n" + " $ %s -f foo.tiff\n" + " $ %s -s localhost -u username -w password -d 50 --debug ALL foo.tiff\n" + "\n" + "For additional information, see:\n" + "http://www.openmicroscopy.org/site/support/omero5.2/users/cli/import.html\n" + "Report bugs to <ome-users@lists.openmicroscopy.org.uk>", APP_NAME, APP_NAME, APP_NAME, APP_NAME, APP_NAME, APP_NAME)); System.exit(1); } /** * Prints advanced usage to STDERR and exits with return code 1. */ public static void advUsage() { System.err.println("\n" + "ADVANCED OPTIONS:\n\n" + " These options are not intended for general use. Make sure you have read the\n" + " documentation regarding them. They may change in future releases.\n\n" + " In-place imports:\n" + " -----------------\n\n" + " --transfer=ARG \tFile transfer method\n\n" + " General options: \t\n" + " upload \t# Default\n" + " upload_rm \t# Caution! File upload followed by source deletion.\n" + " some.class.Name \t# Use a class on the CLASSPATH.\n\n" + " Server-side options:\t\n" + " ln \t# Use hard-link.\n" + " ln_s \t# Use soft-link.\n" + " ln_rm \t# Caution! Hard-link followed by source deletion.\n" + " cp \t# Use local copy command.\n" + " cp_rm \t# Caution! Copy followed by source deletion.\n\n" + "\n" + " e.g. $ bin/omero import -- --transfer=ln_s foo.tiff\n" + " $ ./importer-cli --transfer=ln bar.tiff\n" + " $ CLASSPATH=mycode.jar ./importer-cli --transfer=com.example.MyTransfer baz.tiff\n" + "\n" + " Background imports:\n" + " -------------------\n\n" + " --auto_close \tClose completed imports immediately.\n\n" + " --minutes_wait=ARG \tChoose how long the importer will wait on server-side processing.\n" + " \tARG > 0 implies the number of minutes to wait.\n" + " \tARG = 0 exits immediately. Use a *_completed option to clean up.\n" + " \tARG < 0 waits indefinitely. This is the default.\n\n" + " --close_completed \tClose completed imports.\n\n" + " --wait_completed \tWait for all background imports to complete.\n\n" + "\n" + " e.g. $ bin/omero import -- --minutes_wait=0 file1.tiff file2.tiff file3.tiff\n" + " $ ./importer-cli --minutes_wait=0 some_directory/\n" + " $ ./importer-cli --wait_completed # Waits on all 3 imports.\n" + "\n" + " File exclusion:\n" + " ---------------\n\n" + " --exclude=filename \tExclude files based on filename.\n\n" + " --exclude=clientpath \tExclude files based on the original path.\n\n" + "\n" + " e.g. $ bin/omero import -- --exclude=filename foo.tiff # First-time imports\n" + " $ bin/omero import -- --exclude=filename foo.tiff # Second-time skips\n" + "\n" + " Import speed:\n" + " -------------\n\n" + " --checksum-algorithm=ARG\tChoose a possibly faster algorithm for detecting file corruption,\n" + " \te.g. Adler-32 (fast), CRC-32 (fast), File-Size-64 (fast),\n" + " \t MD5-128, Murmur3-32, Murmur3-128,\n" + " \t SHA1-160 (slow, default)\n\n" + " e.g. $ bin/omero import -- --checksum-algorithm=CRC-32 foo.tiff\n" + " $ ./importer-cli --checksum-algorithm=Murmur3-128 bar.tiff\n\n" + " --no-stats-info\t\tDisable calculation of minima and maxima" + " when as part of the Bio-Formats reader metadata\n\n" + " e.g. $ bin/omero import -- --no-stats-info foo.tiff\n" + " $ ./importer-cli --no-stats-info bar.tiff\n\n" + " --no-thumbnails\t\tDo not perform thumbnailing after import\n\n" + " e.g. $ bin/omero import -- --no-thumbnails foo.tiff\n" + " $ ./importer-cli --no-thumbnails bar.tiff\n\n" + " --no-upgrade-check\t\tDisable upgrade check for each import\n" + " e.g. $ bin/omero import -- --no-upgrade-check foo.tiff\n" + " $ ./importer-cli --no-upgrade-check bar.tiff\n\n" + "\n" + " Feedback:\n" + " ---------\n\n" + " --qa-baseurl=ARG\tSpecify the base URL for reporting feedback\n" + " e.g. $ bin/omero import broken_image.tif" + " -- --email EMAIL --report --upload --logs" + " --qa-baseurl=https://qa.staging.openmicroscopy.org/qa\n" + " $ ./importer-cli broken_image.tif" + " --email EMAIL --report --upload --logs" + " --qa-baseurl=https://qa.staging.openmicroscopy.org/qa\n" + "\n" + "Report bugs to <ome-users@lists.openmicroscopy.org.uk>"); System.exit(1); } /** * Takes pairs of namespaces and string and creates comment annotations * from each pair. * @param namespaces Namespaces to use. * @param strings Strings to use. * @return List of comment annotations. */ private static List<Annotation> toTextAnnotations( List<String> namespaces, List<String> strings) { if (namespaces.size() != strings.size()) { throw new IllegalArgumentException(String.format( "#Namespaces:%d != #Text:%d", namespaces.size(), strings.size())); } List<Annotation> annotations = new ArrayList<Annotation>(); for(int i = 0; i < namespaces.size(); i++) { CommentAnnotationI annotation = new CommentAnnotationI(); annotation.setNs(omero.rtypes.rstring(namespaces.get(i))); annotation.setTextValue(omero.rtypes.rstring(strings.get(i))); annotations.add(annotation); } return annotations; } /** * Command line application entry point which parses CLI arguments and * passes them into the importer. Return codes for import are: * <ul> * <li>0 on success</li> * <li>1 on argument parsing failure</li> * <li>2 on exception during import</li> * </ul> * * Return codes for the "-f" option (getUsedFiles) are: * <ul> * <li>0 on success, even if errors exist in the files</li> * <li>1 only if an exception propagates up the stack</li> * </ul> * @param args * Command line arguments. * @throws Exception in the event of error */ public static void main(String[] args) throws Exception { int minutesToWait = DEFAULT_WAIT; FileTransfer transfer = new UploadFileTransfer(); ImportConfig config = new ImportConfig(); // Defaults config.email.set(""); config.sendFiles.set(false); config.sendLogFile.set(false); config.sendReport.set(false); config.contOnError.set(false); config.debug.set(false); config.encryptedConnection.set(false); LongOpt debug = new LongOpt( "debug", LongOpt.OPTIONAL_ARGUMENT, null, 1); LongOpt report = new LongOpt("report", LongOpt.NO_ARGUMENT, null, 2); LongOpt upload = new LongOpt("upload", LongOpt.NO_ARGUMENT, null, 3); LongOpt logs = new LongOpt("logs", LongOpt.NO_ARGUMENT, null, 4); LongOpt email = new LongOpt( "email", LongOpt.REQUIRED_ARGUMENT, null, 5); LongOpt name = new LongOpt( "name", LongOpt.REQUIRED_ARGUMENT, null, 6); LongOpt description = new LongOpt( "description", LongOpt.REQUIRED_ARGUMENT, null, 7); LongOpt noThumbnails = new LongOpt( "no-thumbnails", LongOpt.NO_ARGUMENT, null, 8); LongOpt agent = new LongOpt( "agent", LongOpt.REQUIRED_ARGUMENT, null, 9); LongOpt annotationNamespace = new LongOpt("annotation-ns", LongOpt.REQUIRED_ARGUMENT, null, 10); LongOpt annotationText = new LongOpt("annotation-text", LongOpt.REQUIRED_ARGUMENT, null, 11); LongOpt annotationLink = new LongOpt("annotation-link", LongOpt.REQUIRED_ARGUMENT, null, 12); // ADVANCED OPTIONS LongOpt advancedHelp = new LongOpt("advanced-help", LongOpt.NO_ARGUMENT, null, 13); LongOpt transferOpt = new LongOpt("transfer", LongOpt.REQUIRED_ARGUMENT, null, 14); LongOpt checksumAlgorithm = new LongOpt("checksum-algorithm", LongOpt.REQUIRED_ARGUMENT, null, 15); LongOpt minutesWait = new LongOpt("minutes_wait", LongOpt.REQUIRED_ARGUMENT, null, 16); LongOpt closeCompleted = new LongOpt("close_completed", LongOpt.NO_ARGUMENT, null, 17); LongOpt waitCompleted = new LongOpt("wait_completed", LongOpt.NO_ARGUMENT, null, 18); LongOpt autoClose = new LongOpt("auto_close", LongOpt.NO_ARGUMENT, null, 19); LongOpt exclude = new LongOpt("exclude", LongOpt.REQUIRED_ARGUMENT, null, 20); LongOpt target = new LongOpt("target", LongOpt.REQUIRED_ARGUMENT, null, 21); LongOpt qaBaseURL = new LongOpt( "qa-baseurl", LongOpt.REQUIRED_ARGUMENT, null, 22); LongOpt noStatsInfo = new LongOpt("no-stats-info", LongOpt.NO_ARGUMENT, null, 23); LongOpt noUpgradeCheck = new LongOpt("no-upgrade-check", LongOpt.NO_ARGUMENT, null, 24); // DEPRECATED OPTIONS LongOpt plateName = new LongOpt( "plate_name", LongOpt.REQUIRED_ARGUMENT, null, 90); LongOpt plateDescription = new LongOpt( "plate_description", LongOpt.REQUIRED_ARGUMENT, null, 91); LongOpt noThumbnailsDeprecated = new LongOpt( "no_thumbnails", LongOpt.NO_ARGUMENT, null, 92); LongOpt checksumAlgorithmDeprecated = new LongOpt( "checksum_algorithm", LongOpt.REQUIRED_ARGUMENT, null, 93); LongOpt annotationNamespaceDeprecated = new LongOpt("annotation_ns", LongOpt.REQUIRED_ARGUMENT, null, 94); LongOpt annotationTextDeprecated = new LongOpt("annotation_text", LongOpt.REQUIRED_ARGUMENT, null, 95); LongOpt annotationLinkDeprecated = new LongOpt("annotation_link", LongOpt.REQUIRED_ARGUMENT, null, 96); Getopt g = new Getopt(APP_NAME, args, "cfl:s:u:w:d:r:T:k:x:n:p:h", new LongOpt[] { debug, report, upload, logs, email, name, description, noThumbnails, agent, annotationNamespace, annotationText, annotationLink, transferOpt, advancedHelp, checksumAlgorithm, minutesWait, closeCompleted, waitCompleted, autoClose, exclude, target, noStatsInfo, noUpgradeCheck, qaBaseURL, plateName, plateDescription, noThumbnailsDeprecated, checksumAlgorithmDeprecated, annotationNamespaceDeprecated, annotationTextDeprecated, annotationLinkDeprecated }); int a; boolean doCloseCompleted = false; boolean doWaitCompleted = false; boolean getUsedFiles = false; config.agent.set("importer-cli"); // Create a map for handling conflicting option strings Map<String, Boolean> conflictingArguments = new HashMap<String, Boolean>(); conflictingArguments.put("userSpecifiedName", false); conflictingArguments.put("userSpecifiedDescription", false); conflictingArguments.put("checksumAlgorithm", false); List<String> annotationNamespaces = new ArrayList<String>(); List<String> textAnnotations = new ArrayList<String>(); List<Long> annotationIds = new ArrayList<Long>(); List<FileExclusion> exclusions = new ArrayList<FileExclusion>(); while ((a = g.getopt()) != -1) { switch (a) { case 1: { config.configureDebug(g.getOptarg()); break; } case 2: { config.sendReport.set(true); break; } case 3: { config.sendFiles.set(true); break; } case 4: { config.sendLogFile.set(true); break; } case 5: { config.email.set(g.getOptarg()); break; } case 6: { setArgument(conflictingArguments, "userSpecifiedName"); config.userSpecifiedName.set(g.getOptarg()); break; } case 7: { setArgument(conflictingArguments, "userSpecifiedDescription"); config.userSpecifiedDescription.set(g.getOptarg()); break; } case 8: { log.info("Skipping thumbnails creation"); config.doThumbnails.set(false); break; } case 9: { config.agent.set(g.getOptarg()); break; } case 10: { annotationNamespaces.add(g.getOptarg()); break; } case 11: { textAnnotations.add(g.getOptarg()); break; } case 12: { annotationIds.add(Long.parseLong(g.getOptarg())); break; } case 13: { advUsage(); break; } // ADVANCED START ------------------------------------------------- case 14: { String arg = g.getOptarg(); log.info("Setting transfer to {}", arg); transfer = AbstractFileTransfer.createTransfer(arg); break; } case 15: { setArgument(conflictingArguments, "checksumAlgorithm"); String arg = g.getOptarg(); log.info("Setting checksum algorithm to {}", arg); config.checksumAlgorithm.set(arg); break; } case 16: { minutesToWait = Integer.parseInt(g.getOptarg()); log.info("Setting minutes to wait to {}", minutesToWait); break; } case 17: { doCloseCompleted = true; break; } case 18: { doWaitCompleted = true; break; } case 19: { minutesToWait = 0; config.autoClose.set(true); break; } case 20: { String arg = g.getOptarg(); log.info("Adding exclusion: {}", arg); FileExclusion exclusion = AbstractFileExclusion.createExclusion(arg); if (exclusion != null) { exclusions.add(exclusion); } break; } case 'T': case 21: { config.target.set(g.getOptarg()); break; } case 22: { config.qaBaseURL.set(g.getOptarg()); break; } case 23: { log.info("Skipping minimum/maximum computation"); config.noStatsInfo.set(true); break; } case 24: { log.info("Disabling upgrade check"); config.checkUpgrade.set(false); break; } // ADVANCED END --------------------------------------------------- // DEPRECATED OPTIONS case 90: { setArgument(conflictingArguments, "userSpecifiedName"); config.userSpecifiedName.set(g.getOptarg()); break; } case 91: { setArgument(conflictingArguments, "userSpecifiedDescription"); config.userSpecifiedDescription.set(g.getOptarg()); break; } case 92: { log.info("Skipping thumbnails creation"); config.doThumbnails.set(false); break; } case 93: { setArgument(conflictingArguments, "checksumAlgorithm"); String arg = g.getOptarg(); log.info("Setting checksum algorithm to {}", arg); config.checksumAlgorithm.set(arg); break; } case 94: { annotationNamespaces.add(g.getOptarg()); break; } case 95: { textAnnotations.add(g.getOptarg()); break; } case 96: { annotationIds.add(Long.parseLong(g.getOptarg())); break; } // END OF DEPRECATED OPTIONS case 's': { config.hostname.set(g.getOptarg()); break; } case 'u': { config.username.set(g.getOptarg()); break; } case 'w': { config.password.set(g.getOptarg()); break; } case 'k': { config.sessionKey.set(g.getOptarg()); break; } case 'p': { config.port.set(Integer.parseInt(g.getOptarg())); break; } case 'd': { String datasetString = g.getOptarg(); if (!datasetString.startsWith("Dataset:")) { datasetString = "Dataset:" + Long.valueOf(datasetString).toString(); } config.target.set(datasetString); break; } case 'r': { String screenString = g.getOptarg(); if (!screenString.startsWith("Screen:")) { screenString = "Screen:" + Long.valueOf(screenString).toString(); } config.target.set(screenString); break; } case 'n': { setArgument(conflictingArguments, "userSpecifiedName"); config.userSpecifiedName.set(g.getOptarg()); break; } case 'x': { setArgument(conflictingArguments, "userSpecifiedDescription"); config.userSpecifiedDescription.set(g.getOptarg()); break; } case 'f': { getUsedFiles = true; break; } case 'c': { config.contOnError.set(true); break; } case 'l': { config.readersPath.set(g.getOptarg()); break; } case 'h': { usage(); // exits } default: { usage(); // exits } } } // Let the user know at what level we're logging log.info(String.format( "Log levels -- Bio-Formats: %s OMERO.importer: %s", ((ch.qos.logback.classic.Logger)LoggerFactory .getLogger("loci")).getLevel(), ((ch.qos.logback.classic.Logger)LoggerFactory .getLogger("ome.formats")).getLevel())); // Start the importer and import the image we've been given String[] rest = new String[args.length - g.getOptind()]; System.arraycopy(args, g.getOptind(), rest, 0, args.length - g.getOptind()); if (doCloseCompleted || doWaitCompleted) { if (rest.length > 0) { log.error("Files found with completed option: "+ Arrays.toString(rest)); System.exit(-2); // EARLY EXIT! } else if (doCloseCompleted) { System.exit(closeCompleted(config)); // EARLY EXIT! } else if (doWaitCompleted) { System.exit(waitCompleted(config)); // EARLY EXIT! } } List<Annotation> annotations = toTextAnnotations(annotationNamespaces, textAnnotations); for (Long id: annotationIds) { CommentAnnotationI unloadedAnnotation = new CommentAnnotationI(id, false); annotations.add(unloadedAnnotation); } config.annotations.set(annotations); CommandLineImporter c = null; int rc = 0; try { if (rest.length == 1 && "-".equals(rest[0])) { rest = stdin(); } c = new CommandLineImporter(config, rest, getUsedFiles, transfer, exclusions, minutesToWait); rc = c.start(); } catch (Throwable t) { log.error("Error during import process.", t); rc = 2; } finally { if (c != null) { c.cleanup(); } } System.exit(rc); } /** * Set a conflicting argument and return the usage if the key is already * set * @param map map of conflicting properties * @param key configuration property to be set */ public static void setArgument(Map <String, Boolean> map, String key) { if (map.get(key)) { // The property has already been set log.error("Conflicting arguments setting {}.", key); usage(); } map.put(key, true); } /** * Reads a list of paths from stdin. * @return the paths */ static String[] stdin() throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); List<String> files = new ArrayList<String>(); while (true) { String str = in.readLine(); if (str == null) { break; } else { str = str.trim(); if (str.length() > 0) { files.add(str); } } } return files.toArray(new String[0]); } } class ImportCloser { private final static Logger log = LoggerFactory.getLogger(ImportCloser.class); List<ImportProcessPrx> imports; int closed = 0; int errors = 0; int processed = 0; ImportCloser(OMEROMetadataStoreClient client) throws Exception { this.imports = getImports(client); } void closeCompleted() { for (ImportProcessPrx imPrx : imports) { try { processed++; String logName = imPrx.toString().split("\\s")[0]; HandlePrx handle = imPrx.getHandle(); if (handle != null) { Response rsp = handle.getResponse(); if (rsp != null) { log.info("Done: {}", logName); imPrx.close(); closed++; continue; } } log.info("Running: {}", logName); } catch (Exception e) { errors++; log.warn("Failure accessing service", e); } } } int getClosed() { return closed; } int getErrors() { return errors; } int getProcessed() { return processed; } private static List<ImportProcessPrx> getImports(OMEROMetadataStoreClient client) throws Exception { final List<ImportProcessPrx> rv = new ArrayList<ImportProcessPrx>(); final ServiceFactoryPrx sf = client.getServiceFactory(); final List<String> active = sf.activeServices(); for (String service : active) { try { final ServiceInterfacePrx prx = sf.getByName(service); final ImportProcessPrx imPrx = ImportProcessPrxHelper.checkedCast(prx); if (imPrx != null) { try { imPrx.ice_ping(); rv.add(imPrx); } catch (Ice.ObjectNotExistException onee) { // ignore } } } catch (Exception e) { log.warn("Failure accessing active service", e); } } return rv; } }