// $HeadURL:
// http://seanderickson1@forge.abcd.harvard.edu/svn/screensaver/branches/iccbl/data-sharing-levels/src/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.iccbl.screensaver.io.screens;
import javax.mail.MessagingException;
import org.apache.commons.cli.OptionBuilder;
import org.apache.log4j.Logger;
import edu.harvard.med.iccbl.screensaver.io.AdminEmailApplication;
import edu.harvard.med.screensaver.ScreensaverConstants;
import edu.harvard.med.screensaver.db.DAOTransaction;
import edu.harvard.med.screensaver.db.DAOTransactionRollbackException;
import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.db.ScreenDAO;
import edu.harvard.med.screensaver.db.ScreenResultsDAO;
import edu.harvard.med.screensaver.io.screenresults.ScreenResultReporter;
import edu.harvard.med.screensaver.io.screens.StudyCreator;
import edu.harvard.med.screensaver.model.screenresults.ScreenResult;
import edu.harvard.med.screensaver.model.screens.Screen;
import edu.harvard.med.screensaver.model.screens.ScreenType;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.model.users.LabHead;
/**
* TODO: Move the transactional code out of this class and into service methods
* Create a studies to count overlapping positives and to count confirmed positive statistics.<br>
* 1. Overlapping positives:<br>
* see [#2268] new column to display # overlapping screens <br>
* Details: <br>
* <br>
* 1. Overlapping positives:<br>
* We want to provide a column in Well Search Results to display the number of screens that
* have marked the well as a positive. I believe we can include even screens
* w/DSL 3 (Private), but we should confirm this. It would be nice to be able to
* calculate this number dynamically, but it almost certainly would not be
* performant. Instead, we'll probably need to pre-compute this and store in the
* database. To avoid creating new infrastructure for this, I propose that we
* simply create a new study that provides a single data column ("annotation
* type") for this pre-computed count. The study can be recreated via a batch
* cron job that runs a command-line app for this purpose. If we come up with
* new cross-screen comparison statistics, we can add them to this study, as
* appropriate, as new data columns. <br>
*/
public class ScreenPositivesCountStudyCreator extends AdminEmailApplication
{
public static final String DEFAULT_SM_STUDY_TITLE = "Reagent Counts for Small Molecule Screens";
public static final String DEFAULT_SM_STUDY_SUMMARY =
"Annotates each small molecule reagent with the number of times " +
"it has been screened, and the count of positive hits per reagent (library well) " +
"across all small molecule screens. This data is based on primary screening data " +
"only and the \"positive\" designations were determined by the " +
"investigator(s) responsible for each screen.";
public static final String DEFAULT_RNAi_STUDY_TITLE = "Reagent Counts for RNAi Screens";
public static final String DEFAULT_RNAi_STUDY_SUMMARY =
"Annotates each RNAi reagent with the number of times it has " +
"been screened, and the count of positive hits per reagent (library well) across " +
"all RNAi Screens. This data is based on primary screening data only and the " +
"\"positive\" designations were determined by the investigator(s) " +
"responsible for each screen.";
public static final String DEFAULT_POSITIVES_ANNOTATION_NAME = "Screen Positives Count";
public static final String DEFAULT_SM_POSITIVES_ANNOTATION_DESC = "Number of times scored as positive across all Small Molecule Screens";
public static final String DEFAULT_RNAi_POSITIVES_ANNOTATION_DESC = "Number of times scored as positive across all RNAi Screens";
public static final String DEFAULT_OVERALL_ANNOTATION_NAME = "Screened Count";
public static final String DEFAULT_SM_OVERALL_ANNOTATION_DESC = "Number of times screened for all Small Molecule Screens";
public static final String DEFAULT_RNAi_OVERALL_ANNOTATION_DESC = "Number of times screened for all RNAi Screens";
public ScreenPositivesCountStudyCreator(String[] cmdLineArgs)
{
super(cmdLineArgs);
}
private static Logger log = Logger.getLogger(ScreenPositivesCountStudyCreator.class);
public static final String[] OPTION_STUDY_TITLE = { "title", "title", "study-title", "Title for the study" };
public static final String[] OPTION_STUDY_SUMMARY = { "summary", "summary", "study-summary", "Summary for the study" };
// public static final String[] OPTION_ANNOTATION_NAME = { "annotation", "name", "annotation-name", "name for the annotation in the study" };
// public static final String[] OPTION_ANNOTATION_DESC = { "annotationdesc", "desc", "annotation-desc", "descriptive name of the annotation" };
public static final String[] OPTION_STUDY_NUMBER = { "number", "number", "study-number",
"Study number (not required, recommended to use default values), (must be unique, unless specifying the \"replace\" option" };
public static final String[] OPTION_SCREEN_TYPE_SM = { "typesm", "", "screen-type-sm",
"create the study for Small Molecule screens" };
public static final String[] OPTION_SCREEN_TYPE_RNAI = { "typernai", "", "screen-type-rnai",
"create the study for RNAi screens" };
public static final String[] OPTION_REPLACE = {
"replace",
"",
"replace-if-exists",
"the default action is to replace the study if it is out of date; as determined by comparing the study date to the date of the latest screen result. If this option is specified, delete the existing study unconditionally." };
public static final String[] TEST_ONLY = { "testonly", "", "test-only", "run the entire operation specified, then roll-back." };
@SuppressWarnings("static-access")
public static void main(String[] args) throws MessagingException
{
final ScreenPositivesCountStudyCreator app = new ScreenPositivesCountStudyCreator(args);
String[] option = OPTION_STUDY_TITLE;
app.addCommandLineOption(OptionBuilder.hasArg()
.withArgName(option[ARG_INDEX])
.withDescription(option[DESCRIPTION_INDEX])
.withLongOpt(option[LONG_OPTION_INDEX])
.create(option[SHORT_OPTION_INDEX]));
option = OPTION_STUDY_NUMBER;
app.addCommandLineOption(OptionBuilder.hasArg().withType(Integer.class)
.withArgName(option[ARG_INDEX])
.withDescription(option[DESCRIPTION_INDEX])
.withLongOpt(option[LONG_OPTION_INDEX])
.create(option[SHORT_OPTION_INDEX]));
option = OPTION_STUDY_SUMMARY;
app.addCommandLineOption(OptionBuilder.hasArg()
.withArgName(option[ARG_INDEX])
.withDescription(option[DESCRIPTION_INDEX])
.withLongOpt(option[LONG_OPTION_INDEX])
.create(option[SHORT_OPTION_INDEX]));
option = OPTION_SCREEN_TYPE_SM;
app.addCommandLineOption(OptionBuilder.withDescription(option[DESCRIPTION_INDEX])
.withLongOpt(option[LONG_OPTION_INDEX])
.create(option[SHORT_OPTION_INDEX]));
option = OPTION_SCREEN_TYPE_RNAI;
app.addCommandLineOption(OptionBuilder.withDescription(option[DESCRIPTION_INDEX])
.withLongOpt(option[LONG_OPTION_INDEX])
.create(option[SHORT_OPTION_INDEX]));
option = OPTION_REPLACE;
app.addCommandLineOption(OptionBuilder.withDescription(option[DESCRIPTION_INDEX])
.withLongOpt(option[LONG_OPTION_INDEX])
.create(option[SHORT_OPTION_INDEX]));
app.addCommandLineOption(OptionBuilder.withDescription(TEST_ONLY[DESCRIPTION_INDEX])
.withLongOpt(TEST_ONLY[LONG_OPTION_INDEX])
.create(TEST_ONLY[SHORT_OPTION_INDEX]));
app.processOptions(/* acceptDatabaseOptions= */true,
/* acceptAdminUserOptions= */true);
log.info("==== Running ScreenPositivesCountStudyCreator: " + app.toString() + "======");
try {
app.execute();
}
catch (Exception e) {
String subject = "Execution failure for " + app.getClass().getName();
String msg = subject + "\n" + app.toString();
app.sendErrorMail(subject, msg, e);
System.exit(1);
}
}
private void execute()
{
final GenericEntityDAO dao = (GenericEntityDAO) getSpringBean("genericEntityDao");
final ScreenResultReporter report = (ScreenResultReporter) getSpringBean("screenResultReporter");
final ScreenResultsDAO screenResultsDao = (ScreenResultsDAO) getSpringBean("screenResultsDao");
final ScreenDAO screenDao = (ScreenDAO) getSpringBean("screenDao");
//TODO: Move the transactional code out of this class and into service methods
dao.doInTransaction(new DAOTransaction() {
public void runTransaction()
{
try {
AdministratorUser admin = findAdministratorUser();
boolean replaceStudyIfExists = isCommandLineFlagSet(OPTION_REPLACE[SHORT_OPTION_INDEX]);
String title = null;
String summary = null;
String annotationDesc = null;
String overallAnnotationDesc = null;
String studyFacilityId = null;
ScreenType screenType = null;
if (isCommandLineFlagSet(OPTION_SCREEN_TYPE_SM[SHORT_OPTION_INDEX])) {
screenType = ScreenType.SMALL_MOLECULE;
studyFacilityId = ScreensaverConstants.DEFAULT_BATCH_STUDY_ID_POSITIVE_COUNT_SM;
if (isCommandLineFlagSet(OPTION_STUDY_NUMBER[SHORT_OPTION_INDEX])) {
studyFacilityId = getCommandLineOptionValue(OPTION_STUDY_NUMBER[SHORT_OPTION_INDEX], String.class);
}
// todo: title = getMessages().getMessage("admin.studies.cross_screen_comparison_study.study_title");
title = DEFAULT_SM_STUDY_TITLE;
summary = DEFAULT_SM_STUDY_SUMMARY;
annotationDesc = DEFAULT_SM_POSITIVES_ANNOTATION_DESC;
overallAnnotationDesc = DEFAULT_SM_OVERALL_ANNOTATION_DESC;
}
if (isCommandLineFlagSet(OPTION_SCREEN_TYPE_RNAI[SHORT_OPTION_INDEX])) {
if (isCommandLineFlagSet(OPTION_SCREEN_TYPE_SM[SHORT_OPTION_INDEX])) {
showHelpAndExit("Must specify either the \"" + OPTION_SCREEN_TYPE_SM[SHORT_OPTION_INDEX] + "\" or the \"" +
OPTION_SCREEN_TYPE_RNAI[SHORT_OPTION_INDEX] + "\" Option");
}
screenType = ScreenType.RNAI;
studyFacilityId = ScreensaverConstants.DEFAULT_BATCH_STUDY_ID_POSITIVE_COUNT_RNAI;
if (isCommandLineFlagSet(OPTION_STUDY_NUMBER[SHORT_OPTION_INDEX])) {
studyFacilityId = getCommandLineOptionValue(OPTION_STUDY_NUMBER[SHORT_OPTION_INDEX], String.class);
}
title = DEFAULT_RNAi_STUDY_TITLE;
summary = DEFAULT_RNAi_STUDY_SUMMARY;
annotationDesc = DEFAULT_RNAi_POSITIVES_ANNOTATION_DESC;
overallAnnotationDesc = DEFAULT_RNAi_OVERALL_ANNOTATION_DESC;
}
if (screenType == null) {
showHelpAndExit("Must specify either the \"" + OPTION_SCREEN_TYPE_SM[SHORT_OPTION_INDEX] + "\" or the \"" +
OPTION_SCREEN_TYPE_RNAI[SHORT_OPTION_INDEX] + "\" Option");
}
if (isCommandLineFlagSet(OPTION_STUDY_TITLE[SHORT_OPTION_INDEX])) {
title = getCommandLineOptionValue(OPTION_STUDY_TITLE[SHORT_OPTION_INDEX]);
}
if (isCommandLineFlagSet(OPTION_STUDY_SUMMARY[SHORT_OPTION_INDEX])) {
summary = getCommandLineOptionValue(OPTION_STUDY_SUMMARY[SHORT_OPTION_INDEX]);
}
Screen study = dao.findEntityByProperty(Screen.class, Screen.facilityId.getPropertyName(), studyFacilityId);
if (study != null) {
// first check if the study is out of date
ScreenResult latestScreenResult = screenResultsDao.getLatestScreenResult();
if (latestScreenResult == null)
{
log.info("No screen results found in the database");
System.exit(0);
}
else if (study.getDateCreated().compareTo(latestScreenResult.getDateCreated()) < 1) {
screenDao.deleteStudy(study);
}
else if (replaceStudyIfExists) {
screenDao.deleteStudy(study);
}
else {
String msg = "study " + studyFacilityId +
" already exists and is up-to-date (as determined by the date of the latest uploaded screen result). " +
"Use the --" + OPTION_REPLACE[LONG_OPTION_INDEX] + " flag to delete the existing study first.";
log.info(msg);
System.exit(0);
}
}
LabHead labHead = (LabHead) StudyCreator.findOrCreateScreeningRoomUser(dao,
admin.getFirstName(),
admin.getLastName(),
admin.getEmail(),
true,
null);
int[] counts = report.createReagentCountStudy(admin,
labHead,
studyFacilityId,
title,
summary,
DEFAULT_POSITIVES_ANNOTATION_NAME,
annotationDesc,
DEFAULT_OVERALL_ANNOTATION_NAME,
overallAnnotationDesc,
screenType);
String subject = "Study created: " + study.getTitle(); //getMessages().getMessage("Study generated");
if (isCommandLineFlagSet(TEST_ONLY[SHORT_OPTION_INDEX])) {
subject = "[TEST ONLY, no commits] " + subject;
}
String msg = "Study: " + study.getFacilityId() + ", " + study.getTitle() + ": " + study.getSummary()
+ "\nscreened reagents: " + counts[1] + ", screened positive reagents: " + counts[0];
sendAdminEmails(subject, msg);
}
catch (MessagingException e) {
throw new DAOTransactionRollbackException(e);
}
if (isCommandLineFlagSet(TEST_ONLY[SHORT_OPTION_INDEX])) {
throw new DAOTransactionRollbackException("Rollback, testing only");
}
}
});
log.info("==== finished ScreenPositivesCountStudyCreator ======");
}
}