edu.harvard.med.screensaver.io.screenresults.ScreenResultImporter.java Source code

Java tutorial

Introduction

Here is the source code for edu.harvard.med.screensaver.io.screenresults.ScreenResultImporter.java

Source

// $HeadURL:
// http://seanderickson1@forge.abcd.harvard.edu/svn/screensaver/branches/lincs/ui-cleanup/core/src/main/java/edu/harvard/med/screensaver/io/screenresults/ScreenResultImporter.java
// $
// $Id$
//
// Copyright  2006, 2010, 2011, 2012 by the President and Fellows of Harvard College.
//
// Screensaver is an open-source project developed by the ICCB-L and NSRB labs
// at Harvard Medical School. This software is distributed under the terms of
// the GNU General Public License.

package edu.harvard.med.screensaver.io.screenresults;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Iterator;

import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang.math.IntRange;
import org.apache.log4j.Logger;

import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.io.CommandLineApplication;
import edu.harvard.med.screensaver.io.ParseError;
import edu.harvard.med.screensaver.io.ParseErrorsException;
import edu.harvard.med.screensaver.io.workbook2.Workbook;
import edu.harvard.med.screensaver.model.screens.Screen;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.service.EntityNotFoundException;
import edu.harvard.med.screensaver.service.screenresult.ScreenResultDeleter;
import edu.harvard.med.screensaver.service.screenresult.ScreenResultLoader;

public class ScreenResultImporter extends CommandLineApplication {
    public ScreenResultImporter(String[] cmdLineArgs) {
        super(cmdLineArgs);
    }

    private static Logger log = Logger.getLogger(ScreenResultImporter.class);

    public static final int SHORT_OPTION = 0;
    public static final int LONG_OPTION = 1;

    static final String[] INPUT_FILE_OPTION = { "f", "input-file" };
    static final String[] SCREEN_OPTION = { "s", "screen" };
    static final String[] IMPORT_OPTION = { "i", "import" };
    static final String[] WELLS_OPTION = { "w", "wells" };
    static final String[] PLATE_NUMBER_START_OPTION = { "sp", "start-plate" };
    static final String[] PLATE_NUMBER_END_OPTION = { "ep", "end-plate" };
    static final String[] IGNORE_DUPLICATE_ERRORS_OPTION = { "ignoreDuplicates", "ignore-duplicate-well-errors" };
    static final String[] INCREMENTAL_FLUSH_OPTION = { "incrementalFlush", "incremental-flush" };
    static final String[] COMMENTS = { "c", "comments",
            "Comments to be recorded for this screen result data loading activity" };
    static final String[] DELETE_EXISTING = { "d", "delete", "Delete existing screen result, if it exists" };

    private static final String ERROR_ANNOTATED_WORKBOOK_FILE_EXTENSION = "errors.xls";

    protected static final String SCREEN_RESULT_IMPORTER_SPRING_CONFIGURATION = "spring-context-screen-result-parser-app.xml";

    @SuppressWarnings("static-access")
    public static void main(String[] args) {
        ScreenResultImporter app = new ScreenResultImporter(args);
        app.addCommandLineOption(OptionBuilder.hasArg().withArgName("screen facility ID").isRequired()
                .withDescription(
                        "the facility-assigned ID of the screen for which the screen result is being parsed")
                .withLongOpt(SCREEN_OPTION[LONG_OPTION]).create(SCREEN_OPTION[SHORT_OPTION]));
        app.addCommandLineOption(OptionBuilder.hasArg().withArgName("file").isRequired()
                .withDescription("the file location of the Excel workbook file holding the Screen Result metadata")
                .withLongOpt(INPUT_FILE_OPTION[LONG_OPTION]).create(INPUT_FILE_OPTION[SHORT_OPTION]));
        app.addCommandLineOption(OptionBuilder.hasArg().withArgName("comments").isRequired(false)
                .withDescription("comments to associate with the data loading activity")
                .withLongOpt(COMMENTS[LONG_OPTION]).create(COMMENTS[SHORT_OPTION]));
        app.addCommandLineOption(OptionBuilder.withDescription("The first plate number to parse/import").hasArg()
                .withArgName("#").withLongOpt(PLATE_NUMBER_START_OPTION[LONG_OPTION])
                .create(PLATE_NUMBER_START_OPTION[SHORT_OPTION]));
        app.addCommandLineOption(OptionBuilder.withDescription("The last plate number to parse/import").hasArg()
                .withArgName("#").withLongOpt(PLATE_NUMBER_END_OPTION[LONG_OPTION])
                .create(PLATE_NUMBER_END_OPTION[SHORT_OPTION]));
        app.addCommandLineOption(OptionBuilder
                .withDescription("Import screen result into database if parsing is successful.  "
                        + "(By default, the parser only validates the input and then exits.)")
                .withLongOpt(IMPORT_OPTION[LONG_OPTION]).create(IMPORT_OPTION[SHORT_OPTION]));
        app.addCommandLineOption(OptionBuilder.withDescription("Ignore any subsequent duplicates of a well")
                .isRequired(false).withLongOpt(IGNORE_DUPLICATE_ERRORS_OPTION[LONG_OPTION])
                .create(IGNORE_DUPLICATE_ERRORS_OPTION[SHORT_OPTION]));

        app.addCommandLineOption(OptionBuilder.withDescription(
                "Set the incremental flushing option; this is necessary for conserving memory in large imports (default=\"true\")")
                .isRequired(false).withArgName("value").withLongOpt(INCREMENTAL_FLUSH_OPTION[LONG_OPTION])
                .create(INCREMENTAL_FLUSH_OPTION[SHORT_OPTION]));
        app.addCommandLineOption(OptionBuilder.withDescription(DELETE_EXISTING[2]).hasArg(false)
                .withLongOpt(DELETE_EXISTING[LONG_OPTION]).create(DELETE_EXISTING[SHORT_OPTION]));

        app.processOptions(/* acceptDatabaseOptions= */true, /* acceptAdminUserOptions= */true);
        try {
            execute(app);
        } catch (ParseErrorsException e) {
            if (!e.getErrors().isEmpty()) {
                for (ParseError pe : e.getErrors()) {
                    log.error("" + pe);
                }
                log.error("" + e.getErrors().size() + " errors found.");
            }
            System.exit(1);
        } catch (Exception e) {
            log.error("Failed to create the screen result", e);
            System.exit(1);
        }

    }

    private static void execute(ScreenResultImporter app)
            throws EntityNotFoundException, FileNotFoundException, ParseException, ParseErrorsException {
        File inputFile;
        GenericEntityDAO dao = (GenericEntityDAO) app.getSpringBean("genericEntityDao");

        // if parse-only mode is requested, use a spring configuration that does not have a database dependency
        if (!app.isCommandLineFlagSet(IMPORT_OPTION[SHORT_OPTION])) { // TODO: this is a bug, since cannot instantiate the spring-application-context after getting the genericEntityDao bean (or any bean) - sde4
            app.setSpringConfigurationResource(SCREEN_RESULT_IMPORTER_SPRING_CONFIGURATION);
        }

        inputFile = app.getCommandLineOptionValue(INPUT_FILE_OPTION[SHORT_OPTION], File.class);

        IntRange plateNumberRange = null;
        if (app.isCommandLineFlagSet(PLATE_NUMBER_START_OPTION[SHORT_OPTION])
                && app.isCommandLineFlagSet(PLATE_NUMBER_END_OPTION[SHORT_OPTION])) {
            plateNumberRange = new IntRange(
                    app.getCommandLineOptionValue(PLATE_NUMBER_START_OPTION[SHORT_OPTION], Integer.class),
                    app.getCommandLineOptionValue(PLATE_NUMBER_END_OPTION[SHORT_OPTION], Integer.class));
            log.info("will parse/load plates " + plateNumberRange);
        }
        final IntRange finalPlateNumberRange = plateNumberRange;

        String screenFacilityId = app.getCommandLineOptionValue(SCREEN_OPTION[SHORT_OPTION]);
        Screen screen = dao.findEntityByProperty(Screen.class, Screen.facilityId.getPropertyName(),
                screenFacilityId);
        if (screen == null) {
            throw new EntityNotFoundException(Screen.class, screenFacilityId);
        }

        Workbook workbook = new Workbook(inputFile);
        ScreenResultLoader screenResultLoader = (ScreenResultLoader) app.getSpringBean("screenResultLoader");
        screenResultLoader
                .setIgnoreDuplicateErrors(app.isCommandLineFlagSet(IGNORE_DUPLICATE_ERRORS_OPTION[SHORT_OPTION]));

        boolean incrementalFlush = true;
        if (app.isCommandLineFlagSet(INCREMENTAL_FLUSH_OPTION[SHORT_OPTION])) {
            log.info("get incrementalFlush value");
            incrementalFlush = app.getCommandLineOptionValue(INCREMENTAL_FLUSH_OPTION[SHORT_OPTION], Boolean.class);
        }

        log.info("incrementalFlush: " + incrementalFlush);

        AdministratorUser admin = app.findAdministratorUser();
        deleteIfNecessary(app, screen, admin);
        String comments = app.getCommandLineOptionValue(COMMENTS[SHORT_OPTION]);
        screenResultLoader.parseAndLoad(screen, workbook, admin, comments, finalPlateNumberRange, incrementalFlush);
    }

    private static void deleteIfNecessary(ScreenResultImporter app, Screen screen, AdministratorUser admin)
            throws ParseException {
        boolean deleteExisting = app.isCommandLineFlagSet(DELETE_EXISTING[SHORT_OPTION]);
        if (deleteExisting && screen.getScreenResult() != null) {
            ScreenResultDeleter screenResultDeleter = (ScreenResultDeleter) app
                    .getSpringBean("screenResultDeleter");
            screenResultDeleter.deleteScreenResult(screen.getScreenResult(), admin);
        }
    }

    @SuppressWarnings("unchecked")
    private static void cleanErrorAnnotatedWorkbooks(File dir) {
        if (!dir.isDirectory()) {
            log.warn("cannot clean the directory '" + dir + "' since it is not a directory");
            return;
        }
        log.info("cleaning directory " + dir);
        Iterator<File> iterator = org.apache.commons.io.FileUtils.iterateFiles(dir,
                new String[] { ERROR_ANNOTATED_WORKBOOK_FILE_EXTENSION, ".out" }, false);
        while (iterator.hasNext()) {
            File fileToDelete = (File) iterator.next();
            log.info("deleting previously generated outputfile '" + fileToDelete + "'");
            fileToDelete.delete();
        }
    }
}