// $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.libraries;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import com.google.common.collect.Lists;
import org.apache.log4j.Logger;
import org.springframework.transaction.annotation.Transactional;
import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.db.LibrariesDAO;
import edu.harvard.med.screensaver.io.ParseError;
import edu.harvard.med.screensaver.io.ParseErrorsException;
import edu.harvard.med.screensaver.io.ParseException;
import edu.harvard.med.screensaver.io.libraries.LibraryContentsParser;
import edu.harvard.med.screensaver.io.libraries.rnai.HairpinLibraryContentsParser;
import edu.harvard.med.screensaver.io.libraries.rnai.RNAiLibraryContentsParser;
import edu.harvard.med.screensaver.io.libraries.smallmolecule.NaturalProductsLibraryContentsParser;
import edu.harvard.med.screensaver.io.libraries.smallmolecule.SmallMoleculeLibraryContentsParser;
import edu.harvard.med.screensaver.model.libraries.Library;
import edu.harvard.med.screensaver.model.libraries.LibraryContentsVersion;
import edu.harvard.med.screensaver.model.libraries.LibraryType;
import edu.harvard.med.screensaver.model.libraries.Reagent;
import edu.harvard.med.screensaver.model.libraries.Well;
import edu.harvard.med.screensaver.model.screens.ScreenType;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.util.DevelopmentException;
import edu.harvard.med.screensaver.util.Pair;
/**
* Service that creates a new library and its wells and imports its well
* contents into the database.
*/
public class LibraryContentsLoader
{
/**
* The number of record to process between flushing to the database, and
* clearing the Hibernate session cache. Larger numbers (may) increase
* performance, while smaller values reduce memory requirements
*/
private static final int FLUSH_BATCH_SIZE = 384;
private static Logger log = Logger.getLogger(LibraryContentsLoader.class);
private GenericEntityDAO _dao;
private LibrariesDAO _librariesDao;
private LibraryContentsVersionManager _libraryContentsVersionManager;
/**
* @motivation for CGLIB2
*/
protected LibraryContentsLoader() {}
public LibraryContentsLoader(GenericEntityDAO dao,
LibrariesDAO librariesDao,
LibraryContentsVersionManager libraryContentsVersionManager)
{
_dao = dao;
_librariesDao = librariesDao;
_libraryContentsVersionManager = libraryContentsVersionManager;
}
@Transactional(rollbackFor = { ParseErrorsException.class, IOException.class })
public LibraryContentsVersion loadLibraryContents(Library library,
AdministratorUser performedBy,
String loadingComments,
InputStream stream)
throws ParseErrorsException, IOException
{
LibraryContentsVersion lcv = _libraryContentsVersionManager.createNewContentsVersion(library, performedBy, loadingComments);
// flush & clear the Hibernate session to ensure that no library child entities
// become referenced by the library or lcv, thereby allowing GC to occur on those entities
_dao.flush();
_dao.clear();
loadLibraryContents(lcv, stream);
return lcv;
}
private void loadLibraryContents(LibraryContentsVersion lcv,
InputStream stream)
throws ParseErrorsException, IOException
{
Library library = _dao.reloadEntity(lcv.getLibrary(), false, Library.wells);
library.resetContents();
// _dao.mergeEntity(library);
LibraryContentsParser<? extends Reagent> parser;
if (library.getScreenType().equals(ScreenType.RNAI)) {
if (library.getLibraryType().equals(LibraryType.SHRNA)) {
parser = new HairpinLibraryContentsParser(_dao, stream, library);
} else {
parser = new RNAiLibraryContentsParser(_dao, stream, library);
}
}
else if (library.getScreenType().equals(ScreenType.SMALL_MOLECULE))
{
if (library.getLibraryType().equals(LibraryType.NATURAL_PRODUCTS)) {
parser = new NaturalProductsLibraryContentsParser(_dao, stream, library);
}
else {
parser = new SmallMoleculeLibraryContentsParser(_dao, stream, library);
}
}
else {
throw new DevelopmentException("unhandled Library Screen Type: " + library.getScreenType() );
}
int nProcessed = 0;
List<ParseError> errors = Lists.newArrayList();
Pair<Well,? extends Reagent> result;
while (true) {
try {
result = parser.parseNext();
if (result == null) {
break;
}
if(result.getSecond() != null) {
_dao.persistEntity(result.getSecond());
}
if(result.getFirst() != null) {
_dao.persistEntity(result.getFirst());
}
if (++nProcessed % FLUSH_BATCH_SIZE == 0) {
// allow GC to occur
_dao.flush();
_dao.clear();
log.info(nProcessed + " record(s) processed with " + errors.size() + " failure(s)...");
}
}
catch (ParseException e) {
++nProcessed;
errors.add(e.getError());
}
}
log.info(nProcessed + " record(s) processed with " + errors.size() + " failure(s)");
if (errors.size() > 0) {
throw new ParseErrorsException(errors);
}
}
}