// $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.ui.cherrypickrequests;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import org.apache.log4j.Logger;
import org.joda.time.LocalDate;
import org.springframework.transaction.annotation.Transactional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import edu.harvard.med.iccbl.screensaver.policy.cherrypicks.RNAiCherryPickRequestAllowancePolicy;
import edu.harvard.med.iccbl.screensaver.policy.cherrypicks.SmallMoleculeCherryPickRequestAllowancePolicy;
import edu.harvard.med.screensaver.db.DAOTransaction;
import edu.harvard.med.screensaver.db.GenericEntityDAO;
import edu.harvard.med.screensaver.db.LibrariesDAO;
import edu.harvard.med.screensaver.db.datafetcher.DataFetcherUtil;
import edu.harvard.med.screensaver.db.datafetcher.EntityDataFetcher;
import edu.harvard.med.screensaver.db.datafetcher.NoOpDataFetcher;
import edu.harvard.med.screensaver.db.hqlbuilder.HqlBuilder;
import edu.harvard.med.screensaver.io.libraries.PlateWellListParser;
import edu.harvard.med.screensaver.io.libraries.PlateWellListParserResult;
import edu.harvard.med.screensaver.model.Entity;
import edu.harvard.med.screensaver.model.activities.Activity;
import edu.harvard.med.screensaver.model.cherrypicks.CherryPickAssayPlate;
import edu.harvard.med.screensaver.model.cherrypicks.CherryPickLiquidTransfer;
import edu.harvard.med.screensaver.model.cherrypicks.CherryPickLiquidTransferStatus;
import edu.harvard.med.screensaver.model.cherrypicks.CherryPickRequest;
import edu.harvard.med.screensaver.model.cherrypicks.LabCherryPick;
import edu.harvard.med.screensaver.model.cherrypicks.ScreenerCherryPick;
import edu.harvard.med.screensaver.model.libraries.Gene;
import edu.harvard.med.screensaver.model.libraries.Reagent;
import edu.harvard.med.screensaver.model.libraries.SilencingReagent;
import edu.harvard.med.screensaver.model.libraries.Well;
import edu.harvard.med.screensaver.model.meta.PropertyPath;
import edu.harvard.med.screensaver.model.meta.RelationshipPath;
import edu.harvard.med.screensaver.model.screens.CherryPickScreening;
import edu.harvard.med.screensaver.model.screens.ScreenType;
import edu.harvard.med.screensaver.model.users.AdministratorUser;
import edu.harvard.med.screensaver.service.cherrypicks.CherryPickRequestAllocator;
import edu.harvard.med.screensaver.service.cherrypicks.CherryPickRequestCherryPicksAdder;
import edu.harvard.med.screensaver.service.cherrypicks.CherryPickRequestPlateMapFilesBuilder;
import edu.harvard.med.screensaver.service.cherrypicks.CherryPickRequestPlateMapper;
import edu.harvard.med.screensaver.service.screens.ScreeningDuplicator;
import edu.harvard.med.screensaver.ui.activities.ActivityViewer;
import edu.harvard.med.screensaver.ui.arch.datatable.column.TableColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.BooleanEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.IntegerEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.IntegerSetEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.TextEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.TextSetEntityColumn;
import edu.harvard.med.screensaver.ui.arch.datatable.model.DataTableModel;
import edu.harvard.med.screensaver.ui.arch.datatable.model.InMemoryDataModel;
import edu.harvard.med.screensaver.ui.arch.datatable.model.InMemoryEntityDataModel;
import edu.harvard.med.screensaver.ui.arch.searchresults.EntityBasedEntitySearchResults;
import edu.harvard.med.screensaver.ui.arch.searchresults.EntitySearchResults;
import edu.harvard.med.screensaver.ui.arch.util.JSFUtils;
import edu.harvard.med.screensaver.ui.arch.view.SearchResultContextEntityViewerBackingBean;
import edu.harvard.med.screensaver.ui.arch.view.aspects.UICommand;
import edu.harvard.med.screensaver.ui.libraries.WellCopyVolumeSearchResults;
/**
* Backing bean for Cherry Pick Request Viewer page.
*
* @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a>
*/
public class CherryPickRequestViewer extends SearchResultContextEntityViewerBackingBean<CherryPickRequest,CherryPickRequest>
{
private static Logger log = Logger.getLogger(CherryPickRequestViewer.class);
static final String RNAI_COLUMNS_GROUP = "RNAi";
static final String SMALL_MOLECULE_COLUMNS_GROUP = "Small Molecule";
protected static final Predicate<String> NOT_EMPTY = Predicates.and(Predicates.notNull(), Predicates.not(Predicates.equalTo("")));
protected enum AssayPlateValidationType {
LIQUID_TRANSFER,
DOWNLOAD,
DEALLOCATION,
SCREENING,
RECREATE_FAILED
};
private CherryPickRequestDetailViewer _cherryPickRequestDetailViewer;
private LibrariesDAO _librariesDao;
private WellCopyVolumeSearchResults _wellCopyVolumesBrowser;
private ActivityViewer _activityViewer;
private PlateWellListParser _plateWellListParser;
private CherryPickRequestCherryPicksAdder _cherryPickRequestCherryPicksAdder;
private CherryPickRequestAllocator _cherryPickRequestAllocator;
private CherryPickRequestPlateMapper _cherryPickRequestPlateMapper;
private CherryPickRequestPlateMapFilesBuilder _cherryPickRequestPlateMapFilesBuilder;
private ScreeningDuplicator _screeningDuplicator;
private SmallMoleculeCherryPickRequestAllowancePolicy _smallMoleculeCherryPickRequestAllowancePolicy;
private RNAiCherryPickRequestAllowancePolicy _rnaiCherryPickRequestAllowancePolicy;
private String _cherryPicksInput;
private EntitySearchResults<ScreenerCherryPick,ScreenerCherryPick,Integer> _screenerCherryPicksSearchResult;
private LabCherryPicksSearchResult _labCherryPicksSearchResult;
private DataModel _assayPlatesDataModel;
private boolean _selectAllAssayPlates = true;
private int _maxQueryInputItems;
/**
* @motivation for CGLIB2
*/
protected CherryPickRequestViewer() {}
public CherryPickRequestViewer(CherryPickRequestViewer thisProxy,
CherryPickRequestDetailViewer cherryPickRequestDetailViewer,
EntitySearchResults<CherryPickRequest,CherryPickRequest,?> cherryPickRequestsBrowser,
LabCherryPicksSearchResult labCherryPicksSearchResult,
ActivityViewer activityViewer,
GenericEntityDAO dao,
LibrariesDAO librariesDao,
WellCopyVolumeSearchResults wellCopyVolumesBrowser,
CherryPickRequestCherryPicksAdder cherryPickRequestCherryPicksAdder,
CherryPickRequestAllocator cherryPickRequestAllocator,
CherryPickRequestPlateMapper cherryPickRequestPlateMapper,
CherryPickRequestPlateMapFilesBuilder cherryPickRequestPlateMapFilesBuilder,
ScreeningDuplicator screeningDuplicator)
{
super(thisProxy,
CherryPickRequest.class,
BROWSE_CHERRY_PICK_REQUESTS,
VIEW_CHERRY_PICK_REQUEST,
dao,
cherryPickRequestsBrowser);
_cherryPickRequestDetailViewer = cherryPickRequestDetailViewer;
_labCherryPicksSearchResult = labCherryPicksSearchResult;
_activityViewer = activityViewer;
_librariesDao = librariesDao;
_wellCopyVolumesBrowser = wellCopyVolumesBrowser;
_cherryPickRequestCherryPicksAdder = cherryPickRequestCherryPicksAdder;
_cherryPickRequestAllocator = cherryPickRequestAllocator;
_cherryPickRequestPlateMapper = cherryPickRequestPlateMapper;
_cherryPickRequestPlateMapFilesBuilder = cherryPickRequestPlateMapFilesBuilder;
_screeningDuplicator = screeningDuplicator;
getIsPanelCollapsedMap().put("screenerCherryPicks", true);
getIsPanelCollapsedMap().put("labCherryPicks", true);
getIsPanelCollapsedMap().put("cherryPickPlates", true);
_labCherryPicksSearchResult.searchForCherryPickRequest(null);
_labCherryPicksSearchResult.setNestedIn(this);
}
protected void buildScreenerCherryPickSearchResult()
{
_screenerCherryPicksSearchResult = new EntityBasedEntitySearchResults<ScreenerCherryPick,Integer>() {
@Override
public void searchAll()
{
initialize();
}
@Override
public List<? extends TableColumn<ScreenerCherryPick,?>> buildColumns()
{
List<TableColumn<ScreenerCherryPick,?>> screenerCherryPicksTableColumns = buildScreenerCherryPicksTableColumns();
_screenerCherryPicksSearchResult.getColumnManager().addAllCompoundSorts(buildScreenerCherryPicksTableCompoundSorts(screenerCherryPicksTableColumns));
return screenerCherryPicksTableColumns;
}
};
_screenerCherryPicksSearchResult.setCurrentScreensaverUser(getCurrentScreensaverUser());
_screenerCherryPicksSearchResult.setMessages(getMessages());
_screenerCherryPicksSearchResult.setApplicationProperties(getApplicationProperties());
_screenerCherryPicksSearchResult.searchAll();
}
protected List<TableColumn<ScreenerCherryPick,?>> buildScreenerCherryPicksTableColumns()
{
List<TableColumn<ScreenerCherryPick,?>> screenerCherryPicksTableColumns = Lists.newArrayList();
screenerCherryPicksTableColumns.add(new TextEntityColumn<ScreenerCherryPick>(
ScreenerCherryPick.screenedWell.to(Well.library).toProperty("shortName"),
"Library Name", "The library name of the well that was originally screened", TableColumn.UNGROUPED) {
@Override
public String getCellValue(ScreenerCherryPick scp) { return scp.getScreenedWell().getLibrary().getShortName(); }
});
screenerCherryPicksTableColumns.add(new IntegerEntityColumn<ScreenerCherryPick>(
ScreenerCherryPick.screenedWell.toProperty("plateNumber"),
"Library Plate", "The library plate number of the well that was originally screened", TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(ScreenerCherryPick scp) { return scp.getScreenedWell().getPlateNumber(); }
});
screenerCherryPicksTableColumns.add(new TextEntityColumn<ScreenerCherryPick>(
ScreenerCherryPick.screenedWell.toProperty("wellName"),
"Screened Well", "The name of the well that was originally screened", TableColumn.UNGROUPED) {
@Override
public String getCellValue(ScreenerCherryPick scp) { return scp.getScreenedWell().getWellName(); }
});
screenerCherryPicksTableColumns.add(new IntegerEntityColumn<ScreenerCherryPick>(
ScreenerCherryPick.labCherryPicks,
"Source wells", "The number of wells to be cherry picked for the screened well", TableColumn.UNGROUPED) {
@Override
public Integer getCellValue(ScreenerCherryPick scp) { return scp.getLabCherryPicks().size(); }
});
screenerCherryPicksTableColumns.add(new ScreenerCherryPickReagentEntityColumn<Reagent,String>(
Reagent.class,
new TextEntityColumn<Reagent>(
Reagent.vendorName,
"Vendor Name",
"The vendor of the reagent in this well",
TableColumn.UNGROUPED) {
@Override
public String getCellValue(Reagent r)
{
return r.getVendorId().getVendorName();
}
}));
screenerCherryPicksTableColumns.add(new ScreenerCherryPickReagentEntityColumn<Reagent,String>(
Reagent.class,
new TextEntityColumn<Reagent>(
Reagent.vendorIdentifier,
"Reagent ID",
"The vendor-assigned identifier for the reagent in this well",
TableColumn.UNGROUPED) {
@Override
public String getCellValue(Reagent r)
{
return r.getVendorId().getVendorIdentifier();
}
}));
screenerCherryPicksTableColumns.add(new BooleanEntityColumn<ScreenerCherryPick>(
ScreenerCherryPick.screenedWell.toProperty("deprecated"),
"Deprecated", "Whether the cherry picked well has been deprecated (and should not have been cherry picked)", TableColumn.UNGROUPED) {
@Override
public Boolean getCellValue(ScreenerCherryPick scp)
{
return scp.getScreenedWell().isDeprecated();
}
});
screenerCherryPicksTableColumns.get(screenerCherryPicksTableColumns.size() - 1).setVisible(false);
screenerCherryPicksTableColumns.add(new TextEntityColumn<ScreenerCherryPick>(
ScreenerCherryPick.screenedWell.to(Well.deprecationActivity).toProperty("comments"),
"Deprecation Reason", "Why the cherry picked well has been deprecated (and should not have been cherry picked)", TableColumn.UNGROUPED) {
@Override
public String getCellValue(ScreenerCherryPick scp)
{
return scp.getScreenedWell().isDeprecated() ? scp.getScreenedWell().getDeprecationActivity().getComments() : null;
}
});
screenerCherryPicksTableColumns.get(screenerCherryPicksTableColumns.size() - 1).setVisible(false);
screenerCherryPicksTableColumns.add(new ScreenerCherryPickReagentEntityColumn<SilencingReagent,Set<String>>(
SilencingReagent.class,
new TextSetEntityColumn<SilencingReagent>(
SilencingReagent.facilityGenes.toProperty("geneName"),
"Gene",
"The name of the gene targeted by the screened well",
RNAI_COLUMNS_GROUP) {
@Override
public Set<String> getCellValue(SilencingReagent r)
{
return r.getFacilityGenes() == null ? null : Sets.newLinkedHashSet(Iterables.filter(Iterables.transform(Iterables.filter(r.getFacilityGenes(), Predicates.notNull()), Gene.ToGeneName), NOT_EMPTY));
}
}));
screenerCherryPicksTableColumns.add(new ScreenerCherryPickReagentEntityColumn<SilencingReagent,Set<Integer>>(
SilencingReagent.class,
new IntegerSetEntityColumn<SilencingReagent>(
SilencingReagent.facilityGenes.toProperty("entrezgeneId"),
"Entrez ID",
"The Entrez ID of the gene targeted by the screened well",
RNAI_COLUMNS_GROUP) {
@Override
public Set<Integer> getCellValue(SilencingReagent r)
{
return r.getFacilityGenes() == null ? null : Sets.newLinkedHashSet(Iterables.filter(Iterables.transform(Iterables.filter(r.getFacilityGenes(), Predicates.notNull()), Gene.ToEntrezgeneId), Predicates.notNull()));
}
}));
screenerCherryPicksTableColumns.add(new ScreenerCherryPickReagentEntityColumn<SilencingReagent,Set<String>>(SilencingReagent.class,
new TextSetEntityColumn<SilencingReagent>(SilencingReagent.facilityGenes.to(Gene.entrezgeneSymbols),
"Entrez Symbol",
"The Entrez symbol of the gene targeted by the screened well",
RNAI_COLUMNS_GROUP) {
@Override
public Set<String> getCellValue(SilencingReagent r)
{
return r.getFacilityGenes() == null ? null : Sets.newLinkedHashSet(Iterables.filter(Iterables.concat(Iterables.filter(Iterables.transform(Iterables.filter(r.getFacilityGenes(), Predicates.notNull()), Gene.ToEntrezgeneSymbols), Predicates.notNull())), NOT_EMPTY));
}
}));
screenerCherryPicksTableColumns.add(new ScreenerCherryPickReagentEntityColumn<SilencingReagent,Set<String>>(SilencingReagent.class,
new TextSetEntityColumn<SilencingReagent>(SilencingReagent.facilityGenes.to(Gene.genbankAccessionNumbers),
"Genbank AccNo",
"The Genbank accession number of the gene targeted by the screened well",
RNAI_COLUMNS_GROUP) {
@Override
public Set<String> getCellValue(SilencingReagent r)
{
return r.getFacilityGenes() == null ? null : Sets.newLinkedHashSet(Iterables.filter(Iterables.concat(Iterables.filter(Iterables.transform(Iterables.filter(r.getFacilityGenes(), Predicates.notNull()), Gene.ToGenbankAccessionNumbers), Predicates.notNull())), NOT_EMPTY));
}
}));
return screenerCherryPicksTableColumns;
}
protected List<List<TableColumn<ScreenerCherryPick,?>>> buildScreenerCherryPicksTableCompoundSorts(List<TableColumn<ScreenerCherryPick,?>> _screenerCherryPicksTableColumns)
{
List<List<TableColumn<ScreenerCherryPick,?>>> _screenerCherryPicksTableCompoundSorts = Lists.newArrayList();
// define compound sorts
_screenerCherryPicksTableCompoundSorts.add(new ArrayList<TableColumn<ScreenerCherryPick,?>>());
_screenerCherryPicksTableCompoundSorts.get(0).add(_screenerCherryPicksTableColumns.get(0));
_screenerCherryPicksTableCompoundSorts.get(0).add(_screenerCherryPicksTableColumns.get(1));
_screenerCherryPicksTableCompoundSorts.add(new ArrayList<TableColumn<ScreenerCherryPick,?>>());
_screenerCherryPicksTableCompoundSorts.get(1).add(_screenerCherryPicksTableColumns.get(1));
_screenerCherryPicksTableCompoundSorts.get(1).add(_screenerCherryPicksTableColumns.get(0));
_screenerCherryPicksTableCompoundSorts.add(new ArrayList<TableColumn<ScreenerCherryPick,?>>());
_screenerCherryPicksTableCompoundSorts.get(2).add(_screenerCherryPicksTableColumns.get(2));
_screenerCherryPicksTableCompoundSorts.get(2).add(_screenerCherryPicksTableColumns.get(0));
_screenerCherryPicksTableCompoundSorts.get(2).add(_screenerCherryPicksTableColumns.get(1));
return _screenerCherryPicksTableCompoundSorts;
}
protected <T extends Entity<Integer>> DataTableModel<T> buildCherryPicksDataTableModel(final Class<T> clazz,
final CherryPickRequest cpr)
{
if (cpr == null) {
return new InMemoryDataModel<T>(new NoOpDataFetcher<T,Integer,PropertyPath<T>>());
}
else {
return new InMemoryEntityDataModel<T,Integer,T>(new EntityDataFetcher<T,Integer>(clazz, getDao()) {
@Override
public void addDomainRestrictions(HqlBuilder hql)
{
DataFetcherUtil.addDomainRestrictions(hql, RelationshipPath.from(clazz).to("cherryPickRequest"), cpr, getRootAlias());
}
});
}
}
@Override
public void initializeEntity(CherryPickRequest cherryPickRequest)
{
// note: eager fetching screenedWell and latestReleasedReagent, since Hibernate otherwise loads them individually, and slowly
getDao().needReadOnly(cherryPickRequest, CherryPickRequest.screenerCherryPicks.to(ScreenerCherryPick.screenedWell).to(Well.latestReleasedReagent));
getDao().needReadOnly(cherryPickRequest, CherryPickRequest.labCherryPicks.to(LabCherryPick.wellVolumeAdjustments));
}
@Override
public void initializeViewer(CherryPickRequest cherryPickRequest)
{
_cherryPickRequestDetailViewer.setEntity(cherryPickRequest);
_labCherryPicksSearchResult.searchForCherryPickRequest(cherryPickRequest);
_cherryPicksInput = null;
getScreenerCherryPicksSearchResult().initialize(buildCherryPicksDataTableModel(ScreenerCherryPick.class, cherryPickRequest));
_screenerCherryPicksSearchResult.getColumnManager().setVisibilityOfColumnsInGroup(RNAI_COLUMNS_GROUP, false); // cherryPickRequest.getScreen().getScreenType() == ScreenType.RNAI
_screenerCherryPicksSearchResult.getColumnManager().setVisibilityOfColumnsInGroup(SMALL_MOLECULE_COLUMNS_GROUP, false);// cherryPickRequest.getScreen().getScreenType() == ScreenType.SMALL_MOLECULE
_assayPlatesDataModel = null;
// set "Cherry Pick Plates" panel to initially expanded, if cherry pick plates have been created
boolean hasCherryPickPlates = cherryPickRequest.getCherryPickAssayPlates().size() > 0;
getIsPanelCollapsedMap().put("cherryPickPlates", !hasCherryPickPlates);
}
public String getCherryPicksInput()
{
return _cherryPicksInput;
}
public void setCherryPicksInput(String cherryPicksInput)
{
_cherryPicksInput = cherryPicksInput;
}
public EntitySearchResults<ScreenerCherryPick,ScreenerCherryPick,Integer> getScreenerCherryPicksSearchResult()
{
if (_screenerCherryPicksSearchResult == null) {
buildScreenerCherryPickSearchResult();
}
return _screenerCherryPicksSearchResult;
}
public LabCherryPicksSearchResult getLabCherryPicksSearchResult()
{
return _labCherryPicksSearchResult;
}
public int getActiveCherryPickPlatesCount()
{
return getEntity().getActiveCherryPickAssayPlates().size();
}
public int getCompletedCherryPickPlatesCount()
{
return getEntity().getCompletedCherryPickAssayPlates().size();
}
public boolean isRnaiScreen()
{
return getEntity().getScreen().getScreenType().equals(ScreenType.RNAI);
}
public DataModel getAssayPlatesDataModel()
{
if (_assayPlatesDataModel == null) {
getDao().doInTransaction(new DAOTransaction() {
@Override
public void runTransaction()
{
CherryPickRequest cpr = getDao().reloadEntity(getEntity(), true);
getDao().needReadOnly(cpr, CherryPickRequest.cherryPickAssayPlates.to(CherryPickAssayPlate.cherryPickLiquidTransfer).to(CherryPickLiquidTransfer.performedBy));
getDao().needReadOnly(cpr, CherryPickRequest.cherryPickAssayPlates.to(CherryPickAssayPlate.cherryPickScreenings).to(Activity.performedBy));
getDao().needReadOnly(cpr, CherryPickRequest.cherryPickAssayPlates.to(CherryPickAssayPlate.cherryPickRequest).to(CherryPickRequest.requestedBy));
getDao().needReadOnly(cpr, CherryPickRequest.requestedBy);
// TODO: this is definitely a bug, but the following call will populate the cpr.requestedBy since it is not working otherwise, outside of this tx;
// an analysis of the output SQL indicates that the cpr.requestedBy fields are being fetched into the returned resultset, so not clear why this is causing a lazy init ex
// Longer term: dispense with this issue by building the assay plate model in memory? see: [#3527] Lazy init exception when viewing Cherry Pick Request
log.info("======================= CPR.requested by: " + cpr.getRequestedBy());
getDao().needReadOnly(cpr, CherryPickRequest.screen);
// HACK: following reln is (only) needed by validateSelectedAssayPlates() in LIQUID_TRANSFER case
getDao().needReadOnly(cpr, CherryPickRequest.cherryPickAssayPlates.to(CherryPickAssayPlate.labCherryPicks).to(LabCherryPick.screenerCherryPick).to(ScreenerCherryPick.screenedWell).to(Well.latestReleasedReagent));
List<AssayPlateRow> rows = new ArrayList<AssayPlateRow>();
for (CherryPickAssayPlate assayPlate : cpr.getCherryPickAssayPlates()) {
AssayPlateRow row = new AssayPlateRow(assayPlate);
row.setSelected(_selectAllAssayPlates);
rows.add(row);
}
_assayPlatesDataModel = new ListDataModel(rows);
}
});
}
return _assayPlatesDataModel;
}
public boolean isSelectAllAssayPlates()
{
return _selectAllAssayPlates;
}
public void setSelectAllAssayPlates(boolean selectAllAssayPlates)
{
_selectAllAssayPlates = selectAllAssayPlates;
}
// JSF application methods
@UICommand
public String addCherryPicksForWells()
{
return doAddCherryPicksForPoolWells(false);
}
@UICommand
public String addCherryPicksForPoolWells()
{
return doAddCherryPicksForPoolWells(true);
}
protected String doAddCherryPicksForPoolWells(boolean deconvoluteToDuplexWells)
{
PlateWellListParserResult result = PlateWellListParser.parseWellsFromPlateWellList(_cherryPicksInput);
if (result.getErrors().size() > 0) {
showMessage("cherryPicks.parseError");
return REDISPLAY_PAGE_ACTION_RESULT;
}
_cherryPickRequestCherryPicksAdder.addCherryPicksForWells(getEntity(),
result.getParsedWellKeys(),
deconvoluteToDuplexWells);
_cherryPickRequestDetailViewer.showAdminWarnings();
return getThisProxy().reload();
}
@UICommand
public String viewCherryPickRequestWellVolumes()
{
return doViewCherryPickRequestWellVolumes(false);
}
@UICommand
public String viewCherryPickRequestWellVolumesForUnfulfilled()
{
return doViewCherryPickRequestWellVolumes(true);
}
private boolean isSomeUnfulfilled() {
for (LabCherryPick lcp : getEntity().getLabCherryPicks()) {
if (lcp.isUnfulfilled())
return true;
}
return false;
}
// For [#3380] Add prompt to manually assign unreserved source copies before
// mapping in the Cherry Pick Request workflow
public String getUnfulfilledPrompt() {
return isSomeUnfulfilled() ? "javascript: return confirm('"
+ getMessage("cherryPicks.someCherryPicksUnfulfillable.overridePrompt") + "');" : "";
}
@UICommand
public String allocateCherryPicks()
{
if (getEntity().getTransferVolumePerWellApproved() == null) {
showMessage("cherryPicks.approvedCherryPickVolumeRequired");
return REDISPLAY_PAGE_ACTION_RESULT;
}
Set<LabCherryPick> unfulfillable = _cherryPickRequestAllocator.allocate(getEntity());
if (unfulfillable.size() == getEntity().getLabCherryPicks().size()) {
showMessage("cherryPicks.allCherryPicksUnfulfillable");
return REDISPLAY_PAGE_ACTION_RESULT;
}
if (unfulfillable.size() > 0) {
showMessage("cherryPicks.someCherryPicksUnfulfillable");
}
return getThisProxy().reload();
}
@UICommand
public String deallocateCherryPicks()
{
_cherryPickRequestAllocator.deallocate(getEntity());
return getThisProxy().reload();
}
@UICommand
@Transactional
public String deallocateCherryPicksByPlate()
{
if (!validateSelectedAssayPlates(AssayPlateValidationType.DEALLOCATION)) {
return REDISPLAY_PAGE_ACTION_RESULT;
}
CherryPickLiquidTransfer cplt = _screeningDuplicator.addCherryPickLiquidTransfer(getEntity().getScreen(),
getScreensaverUser(),
(AdministratorUser) getScreensaverUser(),
CherryPickLiquidTransferStatus.CANCELED);
for (CherryPickAssayPlate plate : getSelectedAssayPlates()) {
cplt.addCherryPickAssayPlate(getDao().reloadEntity(plate));
}
_cherryPickRequestAllocator.deallocateAssayPlates(cplt.getCherryPickAssayPlates());
getDao().clear(); // detach new Activity, as it should only be persisted if user invokes "save" command
return _activityViewer.editNewEntity(cplt);
}
@UICommand
public String plateMapCherryPicks()
{
if (getEntity().getAssayPlateType() == null) {
showMessage("cherryPicks.assayPlateTypeRequired");
return REDISPLAY_PAGE_ACTION_RESULT;
}
_cherryPickRequestPlateMapper.generatePlateMapping(getEntity());
return getThisProxy().reload();
}
@SuppressWarnings("unchecked")
@UICommand
public String selectAllAssayPlates()
{
List<AssayPlateRow> data = (List<AssayPlateRow>) getAssayPlatesDataModel().getWrappedData();
for (AssayPlateRow row : data) {
row.setSelected(_selectAllAssayPlates);
}
return REDISPLAY_PAGE_ACTION_RESULT;
}
@UICommand
@Transactional
public String downloadPlateMappingFilesForSelectedAssayPlates() throws IOException
{
if (!validateSelectedAssayPlates(AssayPlateValidationType.DOWNLOAD)) {
return REDISPLAY_PAGE_ACTION_RESULT;
}
final Set<CherryPickAssayPlate> plateNames = getSelectedAssayPlates();
if (plateNames.size() == 0) {
showMessage("cherryPicks.noPlatesSelected", "assayPlatesTable");
return REDISPLAY_PAGE_ACTION_RESULT;
}
CherryPickRequest cherryPickRequest = getDao().reloadEntity(getEntity());
if (cherryPickRequest != null) {
InputStream zipStream = _cherryPickRequestPlateMapFilesBuilder.buildZip(cherryPickRequest, plateNames);
JSFUtils.handleUserDownloadRequest(getFacesContext(),
zipStream,
"CherryPickRequest" + cherryPickRequest.getEntityId() + "_PlateMapFiles.zip",
"application/zip");
}
return REDISPLAY_PAGE_ACTION_RESULT;
}
@UICommand
@Transactional
public String recordSuccessfulCreationOfAssayPlates()
{
if (!validateSelectedAssayPlates(AssayPlateValidationType.LIQUID_TRANSFER)) {
return REDISPLAY_PAGE_ACTION_RESULT;
}
CherryPickLiquidTransfer cplt = _screeningDuplicator.addCherryPickLiquidTransfer(getEntity().getScreen(),
getScreensaverUser(),
(AdministratorUser) getScreensaverUser(),
CherryPickLiquidTransferStatus.SUCCESSFUL);
for (CherryPickAssayPlate plate : getSelectedAssayPlates()) {
cplt.addCherryPickAssayPlate(plate);
}
getDao().clear(); // detach new Activity, as it should only be persisted if user invokes "save" command
return _activityViewer.editNewEntity(cplt);
}
@UICommand
@Transactional
public String recordScreeningOfAssayPlates()
{
if (!validateSelectedAssayPlates(AssayPlateValidationType.SCREENING)) {
return REDISPLAY_PAGE_ACTION_RESULT;
}
CherryPickScreening screening = _screeningDuplicator.addCherryPickScreening(getEntity().getScreen(),
getEntity().getRequestedBy(),
(AdministratorUser) getScreensaverUser(),
getEntity());
for (CherryPickAssayPlate plate : getSelectedAssayPlates()) {
screening.addCherryPickAssayPlateScreened(getDao().reloadEntity(plate));
}
getDao().clear(); // detach new Activity, as it should only be persisted if user invokes "save" command
return _activityViewer.editNewEntity(screening);
}
@UICommand
@Transactional
public String recordFailedCreationOfAssayPlates()
{
if (!validateSelectedAssayPlates(AssayPlateValidationType.LIQUID_TRANSFER)) {
return REDISPLAY_PAGE_ACTION_RESULT;
}
CherryPickLiquidTransfer cplt = _screeningDuplicator.addCherryPickLiquidTransfer(getEntity().getScreen(),
getScreensaverUser(),
(AdministratorUser) getScreensaverUser(),
CherryPickLiquidTransferStatus.FAILED);
for (CherryPickAssayPlate plate : getSelectedAssayPlates()) {
cplt.addCherryPickAssayPlate(plate);
}
getDao().clear(); // detach new Activity, as it should only be persisted if user invokes "save" command
return _activityViewer.editNewEntity(cplt);
}
@UICommand
public String createNewAssayPlatesForFailed()
{
if (!validateSelectedAssayPlates(AssayPlateValidationType.RECREATE_FAILED)) {
return REDISPLAY_PAGE_ACTION_RESULT;
}
Set<LabCherryPick> unfulfillable = _cherryPickRequestAllocator.reallocateAssayPlates(getSelectedAssayPlates());
if (!unfulfillable.isEmpty()) {
showMessage("cherryPicks.someCherryPicksUnfulfillable");
}
getDao().flush(); // HACK: only necessary because we're called from LabActivityViewer.postEditAction(), which is already in a txn
return reload();
}
@UICommand
@Transactional
public String createNewCherryPickRequestForUnfulfilledCherryPicks()
{
CherryPickRequest cherryPickRequest = getDao().reloadEntity(getEntity());
// Note reload of cherry pick may have created a proxy for the current user already: reload detached user into session
AdministratorUser currentUser = getDao().reloadEntity((AdministratorUser) getScreensaverUser());
CherryPickRequest newCherryPickRequest = cherryPickRequest.getScreen().createCherryPickRequest(currentUser);
newCherryPickRequest.setComments("Created for unfulfilled cherry picks in Cherry Pick Request " +
cherryPickRequest.getCherryPickRequestNumber());
// TODO: this might be better done in a copy constructor
newCherryPickRequest.setTransferVolumePerWellApproved(cherryPickRequest.getTransferVolumePerWellApproved());
newCherryPickRequest.setTransferVolumePerWellRequested(cherryPickRequest.getTransferVolumePerWellRequested());
newCherryPickRequest.setVolumeApprovedBy(cherryPickRequest.getVolumeApprovedBy());
newCherryPickRequest.setDateVolumeApproved(cherryPickRequest.getDateVolumeApproved());
newCherryPickRequest.setDateRequested(new LocalDate());
newCherryPickRequest.setRandomizedAssayPlateLayout(cherryPickRequest.isRandomizedAssayPlateLayout());
newCherryPickRequest.addEmptyWellsOnAssayPlate(cherryPickRequest.getEmptyWellsOnAssayPlate());
newCherryPickRequest.setRequestedBy(cherryPickRequest.getRequestedBy());
// note: we can only instantiate one new ScreenerCherryPick per *set*
// of LabCherryPicks from the same screenedWell, otherwise we'll
// (appropriately) get a DuplicateEntityException
for (ScreenerCherryPick screenerCherryPick : cherryPickRequest.getScreenerCherryPicks()) {
ScreenerCherryPick newScreenerCherryPick = null;
for (LabCherryPick labCherryPick : screenerCherryPick.getLabCherryPicks()) {
if (!labCherryPick.isAllocated() && !labCherryPick.isCancelled()) {
if (newScreenerCherryPick == null) {
newScreenerCherryPick = newCherryPickRequest.createScreenerCherryPick(labCherryPick.getScreenerCherryPick().getScreenedWell());
}
newScreenerCherryPick.createLabCherryPick(labCherryPick.getSourceWell());
}
}
}
getDao().saveOrUpdateEntity(newCherryPickRequest);
getDao().flush();
return getThisProxy().viewEntity(newCherryPickRequest);
}
@SuppressWarnings("unchecked")
protected Set<CherryPickAssayPlate> getSelectedAssayPlates()
{
Set<CherryPickAssayPlate> selectedAssayPlates = new HashSet<CherryPickAssayPlate>();
List<AssayPlateRow> data = (List<AssayPlateRow>) getAssayPlatesDataModel().getWrappedData();
for (AssayPlateRow row : data) {
if (row.isSelected()) {
selectedAssayPlates.add(row.getData());
}
}
return selectedAssayPlates;
}
@SuppressWarnings("unchecked")
protected boolean validateSelectedAssayPlates(AssayPlateValidationType validationType)
{
Set<CherryPickAssayPlate> selectedAssayPlates = getSelectedAssayPlates();
if (selectedAssayPlates.size() == 0) {
showMessage("cherryPicks.noPlatesSelected", "assayPlatesTable");
return false;
}
boolean adjustSelection = false;
for (Iterator<CherryPickAssayPlate> iter = selectedAssayPlates.iterator(); iter.hasNext();) {
CherryPickAssayPlate assayPlate = iter.next();
switch (validationType) {
case DEALLOCATION: {
if (assayPlate.isFailed() || assayPlate.isPlated() || assayPlate.isCancelled()) {
showMessageForComponent("cherryPicks.deallocateActiveMappedPlatesOnly",
"assayPlatesTable",
assayPlate.getName());
iter.remove();
adjustSelection = true;
}
break;
}
case DOWNLOAD: {
if (assayPlate.isFailed()) {
showMessageForComponent("cherryPicks.downloadActiveMappedPlatesOnly",
"assayPlatesTable",
assayPlate.getName());
iter.remove();
adjustSelection = true;
}
break;
}
case LIQUID_TRANSFER: {
if (assayPlate.getLabCherryPicks().size() == 0) {
// this can happen if an assay plate failed, was re-run, but no lab cherry picks could be allocated for the new plate
iter.remove();
showMessageForComponent("cherryPicks.assayPlateEmpty",
"assayPlatesTable",
assayPlate.getName());
adjustSelection = true;
}
else if (assayPlate.isPlated() || assayPlate.isFailed() || assayPlate.isCancelled()) {
iter.remove();
showMessageForComponent("cherryPicks.assayPlateAlreadyPlatedFailedCanceled",
"assayPlatesTable",
assayPlate.getName());
adjustSelection = true;
}
break;
}
case RECREATE_FAILED: {
if (!assayPlate.isFailed() || !getEntity().getActiveCherryPickAssayPlates().contains(assayPlate)) {
iter.remove();
showMessageForComponent("cherryPicks.assayPlateNotFailedOrAlreadyRecreated",
"assayPlatesTable",
assayPlate.getName());
adjustSelection = true;
}
break;
}
case SCREENING: {
if (!assayPlate.isPlated() && !assayPlate.isPlatedAndScreened()) {
iter.remove();
showMessageForComponent("cherryPicks.assayPlateNotScreenable",
"assayPlatesTable",
assayPlate.getName());
adjustSelection = true;
}
break;
}
}
}
if (adjustSelection) {
List<AssayPlateRow> data = (List<AssayPlateRow>) getAssayPlatesDataModel().getWrappedData();
for (AssayPlateRow row : data) {
if (row.isSelected() && !selectedAssayPlates.contains(row.getData())) {
row.setSelected(false);
}
}
}
return !adjustSelection;
}
protected String doViewCherryPickRequestWellVolumes(boolean forUnfulfilledOnly)
{
_wellCopyVolumesBrowser.searchWellsForCherryPickRequest(getEntity(), forUnfulfilledOnly);
return BROWSE_WELL_VOLUMES;
}
public boolean isSourcePlateReloadRequired()
{
return _cherryPickRequestPlateMapper.getAssayPlatesRequiringSourcePlateReload(getEntity()).size() > 0;
}
}