// $HeadURL$ // $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.service.screenresult; import javax.persistence.EntityExistsException; import com.google.common.collect.Sets; import org.apache.commons.lang.math.IntRange; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import edu.harvard.med.screensaver.db.GenericEntityDAO; import edu.harvard.med.screensaver.db.ScreenResultsDAO; import edu.harvard.med.screensaver.io.ParseErrorsException; import edu.harvard.med.screensaver.io.screenresults.ScreenResultParser; import edu.harvard.med.screensaver.io.workbook2.Workbook; import edu.harvard.med.screensaver.model.activities.AdministrativeActivity; import edu.harvard.med.screensaver.model.screenresults.ScreenResult; 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.screens.ScreenDerivedPropertiesUpdater; /** * Loads a {@link ScreenResult} into the database. This class wraps * {@link ScreenResultParser}, and is responsible for making newly parsed * {@link ScreenResult}s persistent. */ public abstract class ScreenResultLoader { private static Logger log = Logger.getLogger(ScreenResultLoader.class); private GenericEntityDAO _dao; private ScreenResultsDAO _screenResultsDao; private ScreenDerivedPropertiesUpdater _screenDerivedPropertiesUpdater; private boolean _ignoreDuplicateErrors; /** * @motivation for CGLIB2 */ protected ScreenResultLoader() {} @Autowired public ScreenResultLoader(GenericEntityDAO dao, ScreenResultsDAO screenResultsDao, ScreenDerivedPropertiesUpdater screenDerivedPropertiesUpdater) { _dao = dao; _screenResultsDao = screenResultsDao; _screenDerivedPropertiesUpdater = screenDerivedPropertiesUpdater; } public void setIgnoreDuplicateErrors(boolean value) { _ignoreDuplicateErrors = value; } /** * @motivation We make use of Spring's "Lookup method injection" feature here * to ensure that we always have a new instance of the parser, * since the parser is stateful and should not be reused. */ abstract protected ScreenResultParser createScreenResultParser(); /** * Load the screen results from a workbook into the database. * @param workbook * @param admin * @param finalPlateNumberRange * @param incrementalFlush force the loader to periodically flush cached ResultValues and other Entities being held by the * Hibernate session. Use this value to limit memory requirements for large datasets. * @throws ParseErrorsException * @throws EntityNotFoundException * @throws EntityExistsException */ @Transactional(propagation=Propagation.REQUIRES_NEW /* to ensure that errors cause rollback */, rollbackFor={ParseErrorsException.class, EntityNotFoundException.class, EntityExistsException.class}) public ScreenResult parseAndLoad(Screen screen, Workbook workbook, AdministratorUser admin, String comments, IntRange finalPlateNumberRange, boolean incrementalFlush) throws ParseErrorsException { screen = _dao.reloadEntity(screen); ScreenResultParser screenResultParser = createScreenResultParser(); screenResultParser.setIgnoreDuplicateErrors(_ignoreDuplicateErrors); ScreenResult screenResult = screenResultParser.parse(screen, workbook, finalPlateNumberRange, incrementalFlush); if (screenResultParser.getHasErrors()) { // we communicate back any parse errors as a ParseErrorsException, as this // serves to rollback the transaction, preventing persistence of invalid // screen result entity throw new ParseErrorsException(screenResultParser.getErrors()); } if (incrementalFlush) { _dao.flush(); _dao.clear(); screen = _dao.reloadEntity(screen); } admin = _dao.reloadEntity(admin); AdministrativeActivity screenResultDataLoading = screen.getScreenResult().createScreenResultDataLoading(admin, screenResultParser.getPlateNumbersLoadedWithMaxReplicates(), comments); int assayPlatesCreated = Sets.difference(screen.getAssayPlatesDataLoaded(), screen.getAssayPlatesScreened()).size(); if (assayPlatesCreated > 0) { log.info("created " + assayPlatesCreated + " assay plate(s) that were not previously recorded as having been screened: " + Sets.difference(screen.getAssayPlatesDataLoaded(), screen.getAssayPlatesScreened())); } _dao.persistEntity(screenResultDataLoading); _screenDerivedPropertiesUpdater.updateScreeningStatistics(screen); log.info("Screen result data loading completed successfully!"); return screenResult; } }