// $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.libraries; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URL; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; import org.apache.log4j.Logger; import org.hibernate.Session; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import edu.harvard.med.lincs.screensaver.LincsScreensaverConstants; import edu.harvard.med.screensaver.ScreensaverConstants; import edu.harvard.med.screensaver.db.Criterion; import edu.harvard.med.screensaver.db.Criterion.Operator; import edu.harvard.med.screensaver.db.GenericEntityDAO; import edu.harvard.med.screensaver.db.LibrariesDAO; import edu.harvard.med.screensaver.db.Query; import edu.harvard.med.screensaver.db.datafetcher.DataFetcher; import edu.harvard.med.screensaver.db.datafetcher.DataFetcherUtil; import edu.harvard.med.screensaver.db.datafetcher.Tuple; import edu.harvard.med.screensaver.db.datafetcher.TupleDataFetcher; import edu.harvard.med.screensaver.db.hqlbuilder.HqlBuilder; import edu.harvard.med.screensaver.db.hqlbuilder.JoinType; import edu.harvard.med.screensaver.io.DataExporter; import edu.harvard.med.screensaver.io.image.ImageLocatorUtil; import edu.harvard.med.screensaver.io.libraries.smallmolecule.LibraryContentsVersionReference; import edu.harvard.med.screensaver.io.libraries.smallmolecule.StructureImageLocator; import edu.harvard.med.screensaver.model.Entity; import edu.harvard.med.screensaver.model.MolarConcentration; import edu.harvard.med.screensaver.model.Volume; import edu.harvard.med.screensaver.model.libraries.Copy; import edu.harvard.med.screensaver.model.libraries.CopyUsageType; import edu.harvard.med.screensaver.model.libraries.Gene; import edu.harvard.med.screensaver.model.libraries.Library; import edu.harvard.med.screensaver.model.libraries.LibraryContentsVersion; import edu.harvard.med.screensaver.model.libraries.LibraryWellType; import edu.harvard.med.screensaver.model.libraries.MolecularFormula; import edu.harvard.med.screensaver.model.libraries.Reagent; import edu.harvard.med.screensaver.model.libraries.SilencingReagent; import edu.harvard.med.screensaver.model.libraries.SilencingReagentType; import edu.harvard.med.screensaver.model.libraries.SmallMoleculeReagent; import edu.harvard.med.screensaver.model.libraries.Well; import edu.harvard.med.screensaver.model.libraries.WellKey; import edu.harvard.med.screensaver.model.meta.PropertyPath; import edu.harvard.med.screensaver.model.meta.RelationshipPath; import edu.harvard.med.screensaver.model.screenresults.AnnotationType; import edu.harvard.med.screensaver.model.screenresults.AnnotationValue; import edu.harvard.med.screensaver.model.screenresults.AssayWell; import edu.harvard.med.screensaver.model.screenresults.AssayWellControlType; import edu.harvard.med.screensaver.model.screenresults.ConfirmedPositiveValue; import edu.harvard.med.screensaver.model.screenresults.DataColumn; import edu.harvard.med.screensaver.model.screenresults.DataType; import edu.harvard.med.screensaver.model.screenresults.MetaDataType; import edu.harvard.med.screensaver.model.screenresults.PartitionedValue; import edu.harvard.med.screensaver.model.screenresults.ResultValue; import edu.harvard.med.screensaver.model.screenresults.ScreenResult; import edu.harvard.med.screensaver.model.screens.LabActivity; import edu.harvard.med.screensaver.model.screens.LibraryScreening; import edu.harvard.med.screensaver.model.screens.Screen; import edu.harvard.med.screensaver.model.screens.ScreenType; import edu.harvard.med.screensaver.model.screens.Study; import edu.harvard.med.screensaver.policy.EntityViewPolicy; import edu.harvard.med.screensaver.ui.arch.datatable.column.ColumnType; import edu.harvard.med.screensaver.ui.arch.datatable.column.TableColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.TableColumnManager; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.BooleanTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.EnumTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.FixedDecimalTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.HasFetchPaths; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.ImageTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.IntegerSetTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.IntegerTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.MolarConcentrationTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.RealTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.TextSetTupleColumn; import edu.harvard.med.screensaver.ui.arch.datatable.column.entity.TextTupleColumn; import edu.harvard.med.screensaver.ui.arch.searchresults.SearchResults; import edu.harvard.med.screensaver.ui.arch.searchresults.TupleBasedEntitySearchResults; import edu.harvard.med.screensaver.ui.arch.util.servlet.ImageProviderServlet; import edu.harvard.med.screensaver.util.NullSafeUtils; import edu.harvard.med.screensaver.util.Triple; import edu.harvard.med.screensaver.util.ValueReference; /** * A {@link SearchResults} for {@link Well Wells}. * * @author <a mailto="john_sullivan@hms.harvard.edu">John Sullivan</a> * @author <a mailto="andrew_tolopko@hms.harvard.edu">Andrew Tolopko</a> */ public abstract class WellSearchResults extends TupleBasedEntitySearchResults<Well,String> { private static final String COLUMN_GENE_SYMBOL = "Entrez Gene Symbol"; private static final String COLUMN_GENE_ID = "Entrez Gene ID"; private static final Logger log = Logger.getLogger(WellSearchResults.class); protected static final String WELL_COLUMNS_GROUP = "Well Columns"; protected static final String SILENCING_REAGENT_COLUMNS_GROUP = "Silencing Reagent Columns"; protected static final String ASSAY_DESCRIPTORS_COLUMNS_GROUP = "Assay Descriptors"; protected static final String COMPOUND_COLUMNS_GROUP = "Compound Reagent Columns"; protected static final String OUR_DATA_COLUMNS_GROUP = "Screen Result Data Columns"; protected static final String OTHER_DATA_COLUMNS_GROUP = "Screen Result Data Columns (Other Screen Results)"; protected static final String OTHER_ANNOTATION_TYPES_COLUMN_GROUP = "Study Annotations (Other Studies)"; protected static final String OUR_ANNOTATION_TYPES_COLUMN_GROUP = "Study Annotations"; protected static final String COLUMN_COMPOUND_NAMES = "Compound Names"; protected static String COLUMN_REAGENT_ID = "Vendor Reagent ID"; private static Joiner fsbColumnValueJoiner = Joiner.on(LincsScreensaverConstants.FACILITY_ID_SEPARATOR); protected static final Function<DataColumn,Triple<DataColumn,String,String>> DataColumnToMetaDataColumn = new Function<DataColumn,Triple<DataColumn,String,String>>() { @Override public Triple<DataColumn,String,String> apply(DataColumn dataColumn) { return new Triple<DataColumn,String,String>(dataColumn, dataColumn.getScreenResult().getScreen().getFacilityId(), dataColumn.getScreenResult().getScreen().getTitle()); } }; protected static final Function<AnnotationType,Triple<AnnotationType,String,String>> AnnotationTypeToMetaAnnotationType = new Function<AnnotationType,Triple<AnnotationType,String,String>>() { @Override public Triple<AnnotationType,String,String> apply(AnnotationType annotType) { return new Triple<AnnotationType,String,String>(annotType, annotType.getStudy().getFacilityId(), annotType.getStudy().getTitle()); } }; /** * @motivation respect EntityViewPolicy logic for restricting structure-related properties on SmallMoleculeReagent, * using only the tuple returned from the database query (and not the full entity) */ private abstract class TuplePropertySmallMoleculeReagent extends SmallMoleculeReagent { private final PropertyPath<Well> _restrictedStructurePropertyPath; private final Tuple<String> _tuple; private TuplePropertySmallMoleculeReagent(PropertyPath<Well> restrictedStructurePropertyPath, Tuple<String> tuple) { _restrictedStructurePropertyPath = restrictedStructurePropertyPath; _tuple = tuple; setEntityViewPolicy(WellSearchResults.this._entityViewPolicy); } public boolean isRestrictedStructure() { Boolean isStructureRestricted = (Boolean) _tuple.getProperty(TupleDataFetcher.makePropertyKey(_restrictedStructurePropertyPath)); return isStructureRestricted != null && isStructureRestricted; } } /** * @motivation respect EntityViewPolicy logic for restricting sequence-related properties on SilencingReagent, using * only the tuple returned from the database query (and not the full entity) */ protected abstract class TuplePropertySilencingReagent extends SilencingReagent { private final PropertyPath<Well> _restrictedSequencePropertyPath; private final Tuple<String> _tuple; protected TuplePropertySilencingReagent(PropertyPath<Well> restrictedSequencePropertyPath, Tuple<String> tuple) { _restrictedSequencePropertyPath = restrictedSequencePropertyPath; _tuple = tuple; setEntityViewPolicy(WellSearchResults.this._entityViewPolicy); } public boolean isRestrictedSequence() { Boolean isSequenceRestricted = (Boolean) _tuple.getProperty(TupleDataFetcher.makePropertyKey(_restrictedSequencePropertyPath)); return isSequenceRestricted != null && isSequenceRestricted; } } protected enum WellSearchResultMode { ALL_WELLS, SET_OF_WELLS, SCREEN_RESULT_WELLS, LIBRARY_WELLS, STUDY_REAGENT_WELLS, SET_OF_REAGENT_WELLS, SET_OF_CANONICAL_REAGENT_WELLS, }; private GenericEntityDAO _dao; private LibrariesDAO _librariesDao; private EntityViewPolicy<Entity> _entityViewPolicy; private LibraryViewer _libraryViewer; protected StructureImageLocator _structureImageLocator; private LibraryContentsVersionReference _libraryContentsVersionRef; protected WellSearchResultMode _mode; protected Set<ScreenType> _screenTypes; protected ScreenResult _screenResult; protected Study _study; protected List<AnnotationType> _validAnnotationTypes = null; /** flag to indicate that this instantiation of WSR is for the LINCS project **/ // TODO: refactor code so that all LINCS-related code is placed into LincsWellSearchResults private Boolean _isLINCS; public class RowsToFetchReference implements ValueReference<Integer> { @Override public Integer value() { return getRowsPerPage(); } } /** * @motivation for CGLIB2 */ protected WellSearchResults() {} /** * Construct a new <code>WellSearchResultsViewer</code> object. */ public WellSearchResults(GenericEntityDAO dao, LibrariesDAO librariesDao, EntityViewPolicy entityViewPolicy, LibraryViewer libraryViewer, WellViewer wellViewer, StructureImageLocator structureImageLocator, LibraryContentsVersionReference libraryContentsVersionRef, List<DataExporter<Tuple<String>>> dataExporters, ImageProviderServlet imageProviderServlet) { super(Well.class, dao, wellViewer); setImageProviderServlet(imageProviderServlet); getDataExporters().addAll(dataExporters); _dao = dao; _librariesDao = librariesDao; _entityViewPolicy = entityViewPolicy; _libraryViewer = libraryViewer; _structureImageLocator = structureImageLocator; _libraryContentsVersionRef = libraryContentsVersionRef; } /** * Called from the top level menu page. * * @motivation Initializes the DataTable with a specialized DataFetcher; causing the bean * to return an empty search result where there all search criteria are undefined */ @Override public void searchAll() { setTitle("Wells Search Result"); setMode(WellSearchResultMode.ALL_WELLS); // initially, show an empty search result, but with all columns available TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public List<String> findAllKeys() { if (!hasCriteriaDefined(getCriteria())) { return Collections.emptyList(); } return super.findAllKeys(); } private boolean hasCriteriaDefined(Map<PropertyPath<Well>,List<? extends Criterion<?>>> criteria) { for (List<? extends Criterion> propCriteria : criteria.values()) { for (Criterion criterion : propCriteria) { if (!criterion.isUndefined()) { return true; } } } return false; } @Override public void addDomainRestrictions(HqlBuilder hql) { hql.from(getRootAlias(), Well.library, "l"); hql.whereIn("l", "libraryType", LibrarySearchResults.LIBRARY_TYPES_TO_DISPLAY); } }; initialize(dataFetcher); // start with search panel open setTableFilterMode(true); } public void searchWellsForLibrary(final Library library) { setTitle("Wells for library " + library.getLibraryName()); setMode(WellSearchResultMode.LIBRARY_WELLS); _screenTypes = ImmutableSet.of(library.getScreenType()); TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public void addDomainRestrictions(HqlBuilder hql) { DataFetcherUtil.addDomainRestrictions(hql, Well.library, library, getRootAlias()); } }; initialize(dataFetcher); setColumnsForScreenType(library.getScreenType()); // start with search panel closed setTableFilterMode(false); } public void searchWellsForLibraryContentsVersion(final LibraryContentsVersion lcv) { setTitle("Wells for library " + lcv.getLibrary().getLibraryName() + ", contents version " + lcv.getVersionNumber()); setMode(WellSearchResultMode.LIBRARY_WELLS); _screenTypes = ImmutableSet.of(lcv.getLibrary().getScreenType()); _libraryContentsVersionRef.setValue(lcv); TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public void addDomainRestrictions(HqlBuilder hql) { DataFetcherUtil.addDomainRestrictions(hql, Well.library, lcv.getLibrary(), getRootAlias()); } }; initialize(dataFetcher); setColumnsForScreenType(lcv.getLibrary().getScreenType()); // start with search panel closed setTableFilterMode(false); } private void setColumnsForScreenType(ScreenType screenType){ // hide SM/RNAi columns depending on the screen type if(screenType == ScreenType.SMALL_MOLECULE) { getColumnManager().getColumn(COLUMN_COMPOUND_NAMES).setVisible(true); } if(screenType == ScreenType.RNAI) { getColumnManager().getColumn(COLUMN_GENE_ID).setVisible(true); getColumnManager().getColumn(COLUMN_GENE_SYMBOL).setVisible(true); } } public void searchWellsForScreenResult(ScreenResult screenResult) { searchWellsForScreenResult(screenResult, false); } public void searchWellsForScreenResult(final ScreenResult screenResult, final boolean filterPositives) { setMode(WellSearchResultMode.SCREEN_RESULT_WELLS); _screenResult = screenResult; _screenTypes = ImmutableSet.of(_screenResult.getScreen().getScreenType()); if (screenResult == null) { initialize(); } else { TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public void addDomainRestrictions(HqlBuilder hql) { hql.from(AssayWell.class, "aw"); hql.where(getRootAlias(), "wellId", Operator.EQUAL, "aw", "libraryWell"); hql.where("aw", "screenResult", Operator.EQUAL, _screenResult); if (filterPositives) { hql.where("aw", "positive", Operator.EQUAL, Boolean.TRUE); } } }; initialize(dataFetcher); // show columns for this screenResult's data columns for (DataColumn dataColumn : screenResult.getDataColumns()) { TableColumn<Tuple<String>,?> column = getColumnManager().getColumn(makeColumnName(dataColumn, screenResult.getScreen().getFacilityId())); if (column != null) { column.setVisible(true); } } setColumnsForScreenType(screenResult.getScreen().getScreenType()); // start with search panel closed setTableFilterMode(false); } } public void searchWellByWellId(final Set<String> wellIds, String title, Set<ScreenType> screenTypes) { setTitle(title); setMode(WellSearchResultMode.SET_OF_WELLS); _screenTypes = screenTypes; TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public void addDomainRestrictions(HqlBuilder hql) { DataFetcherUtil.addDomainRestrictions(hql, getRootAlias(), "wellId", wellIds); } }; initialize(dataFetcher); // start with search panel closed setTableFilterMode(false); // TODO: should report # of well keys not found } public void searchWells(Set<WellKey> wellKeys, String title) { setTitle(title); setMode(WellSearchResultMode.SET_OF_WELLS); _screenTypes = _librariesDao.findScreenTypesForWells(wellKeys); final Set<String> wellKeyStrings = new HashSet<String>(wellKeys.size()); for (WellKey wellKey : wellKeys) { wellKeyStrings.add(wellKey.toString()); } TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public void addDomainRestrictions(HqlBuilder hql) { DataFetcherUtil.addDomainRestrictions(hql, getRootAlias(), wellKeyStrings); } }; initialize(dataFetcher); // start with search panel closed setTableFilterMode(false); // TODO: should report # of well keys not found } public void searchReagentsForStudy(final Study study) { setMode(WellSearchResultMode.STUDY_REAGENT_WELLS); _study = study; _screenTypes = Sets.newHashSet(_study.getScreenType()); TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public void addDomainRestrictions(HqlBuilder hql) { DataFetcherUtil.addDomainRestrictions(hql, Well.reagents.to(Reagent.studies), study, getRootAlias()); } }; initialize(dataFetcher); getColumnManager().getColumn("Reagent Vendor").setVisible(true); getColumnManager().getColumn(COLUMN_REAGENT_ID).setVisible(true); showAnnotationTypesForStudy(study); } public void showAnnotationTypesForStudy(final Study study) { // show columns for this screenResult's data columns for (AnnotationType at : study.getAnnotationTypes()) { getColumnManager().getColumn(WellSearchResults.makeColumnName(at, study.getFacilityId())).setVisible(true); } } public void searchReagentsByVendorIdentifier(final Set<String> reagentIds) { setMode(WellSearchResultMode.SET_OF_REAGENT_WELLS); _screenTypes = _librariesDao.findScreenTypesForReagents(reagentIds); TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public void addDomainRestrictions(HqlBuilder hql) { hql.from(getRootAlias(), Well.reagents, "r").whereIn("r", Reagent.vendorIdentifier.getPropertyName(), reagentIds); } }; initialize(dataFetcher); getColumnManager().getColumn("Reagent Vendor").setVisible(true); getColumnManager().getColumn(COLUMN_REAGENT_ID).setVisible(true); // TODO: should report # of reagent identifiers not found } public void searchAllReagents() { setMode(WellSearchResultMode.LIBRARY_WELLS); setTitle("Browse Reagent Wells"); TupleDataFetcher<Well,String> dataFetcher = new TupleDataFetcher<Well,String>(Well.class, _dao) { @Override public void addDomainRestrictions(HqlBuilder hql) { hql.from(getRootAlias(), Well.reagents, "r").where("r", "vendorId.vendorIdentifier", Operator.NOT_EMPTY, null); } }; initialize(dataFetcher); getColumnManager().getColumn("Reagent Vendor").setVisible(true); getColumnManager().getColumn(COLUMN_REAGENT_ID).setVisible(true); } protected void setMode(WellSearchResultMode mode) { _mode = mode; _study = null; _screenResult = null; _libraryContentsVersionRef.setValue(null); _screenTypes = Sets.newHashSet(ScreenType.values()); _validAnnotationTypes = null; screeningCopyDilutionFactors = null; } protected abstract void initialize(DataFetcher<Tuple<String>,String,PropertyPath<Well>> dataFetcher); @Override protected List<? extends TableColumn<Tuple<String>,?>> buildColumns() { List<TableColumn<Tuple<String>,?>> columns = Lists.newArrayList(); if (isLINCS()) { if (_mode == WellSearchResultMode.SET_OF_CANONICAL_REAGENT_WELLS) { buildWellPropertyColumns(columns); buildReagentPropertyColumns(columns); buildCompoundPropertyColumns(columns); buildSilencingReagentPropertyColumns(columns); } else { buildCompoundPropertyColumns(columns); buildWellPropertyColumns(columns); buildReagentPropertyColumns(columns); buildSilencingReagentPropertyColumns(columns); } } else { buildWellPropertyColumns(columns); buildReagentPropertyColumns(columns); buildCompoundPropertyColumns(columns); buildSilencingReagentPropertyColumns(columns); } // Split the column list so that we can put the other data columns after the annotations // (see: [#2266] command to auto-select data headers for positives from mutual positives screens, // wherein the annotation goes before the other data columns) - sde4 List<DataColumn> dataColumns = Lists.newLinkedList(); List<DataColumn> otherDataColumns = Lists.newLinkedList(); Screen thisScreen = _screenResult == null ? null : _screenResult.getScreen(); for (DataColumn entry : findValidDataColumns()) { if (entry.getScreenResult().getScreen().equals(thisScreen)) { dataColumns.add(entry); } else { otherDataColumns.add(entry); } } buildDataColumns(columns, dataColumns); buildAnnotationTypeColumns(columns); buildDataColumns(columns, otherDataColumns); return columns; } protected void buildSilencingReagentPropertyColumns(List<TableColumn<Tuple<String>,?>> columns) { RelationshipPath<Well> relPath = getWellToReagentRelationshipPath(); columns.add(new EnumTupleColumn<Well,String,SilencingReagentType>( relPath.toProperty("silencingReagentType"), "Silencing Reagent Type", "The Silencing Reagent Type", SILENCING_REAGENT_COLUMNS_GROUP, SilencingReagentType.values())); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextSetTupleColumn<Well,String>( relPath.to(SilencingReagent.facilityGenes).toProperty("geneName"), "Gene Name", "The gene name for the silencing reagent in the well", SILENCING_REAGENT_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new IntegerSetTupleColumn<Well,String>( relPath.to(SilencingReagent.facilityGenes).toProperty("entrezgeneId"), COLUMN_GENE_ID, "The Entrez gene ID for the gene targeted by silencing reagent in the well", SILENCING_REAGENT_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextSetTupleColumn<Well,String>(relPath.to(SilencingReagent.facilityGenes).to(Gene.entrezgeneSymbols), COLUMN_GENE_SYMBOL, "The Entrez gene symbol for the gene targeted by silencing reagent in the well", SILENCING_REAGENT_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextSetTupleColumn<Well,String>(relPath.to(SilencingReagent.facilityGenes).to(Gene.genbankAccessionNumbers), "Genbank Accession Numbers", "The Genbank Accession Numbers for the gene targeted by silencing reagent in the well", SILENCING_REAGENT_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); final PropertyPath<Well> restrictedSequencePropertyPath = relPath.toProperty("restrictedSequence"); columns.add(new TextTupleColumn<Well,String>( relPath.toProperty("sequence"), "Sense Sequence", "The nucleotide sense sequence of this silencing reagent", SILENCING_REAGENT_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { final String sequence = super.getCellValue(tuple); return ((SilencingReagent) new TuplePropertySilencingReagent(restrictedSequencePropertyPath, tuple) { @Override public String getSequence() { return sequence; } }.restrict()).getSequence(); } }); columns.get(columns.size() - 1).setVisible(false); ((TextTupleColumn<Well,String>) Iterables.getLast(columns)).addRelationshipPath(restrictedSequencePropertyPath); columns.add(new TextTupleColumn<Well,String>( relPath.toProperty("antiSenseSequence"), "Anti-sense Sequence", "The nucleotide anti-sense sequence of this silencing reagent", SILENCING_REAGENT_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { final String sequence = super.getCellValue(tuple); return ((SilencingReagent) new TuplePropertySilencingReagent(restrictedSequencePropertyPath, tuple) { @Override public String getAntiSenseSequence() { return sequence; } }.restrict()).getAntiSenseSequence(); } }); columns.get(columns.size() - 1).setVisible(false); ((TextTupleColumn<Well,String>) Iterables.getLast(columns)).addRelationshipPath(restrictedSequencePropertyPath); columns.add(new TextSetTupleColumn<Well,String>( relPath.to(SilencingReagent.facilityGenes).toProperty("speciesName"), "Species", "The species of this silencing reagent", SILENCING_REAGENT_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextSetTupleColumn<Well,String>(relPath.to(SilencingReagent.duplexWells).toProperty("wellId"), "Duplex Wells", "The duplex wells to which this pool well deconvolutes", SILENCING_REAGENT_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); } protected RelationshipPath<Well> getWellToReagentRelationshipPath() { RelationshipPath<Well> relPath; if (accessSpecificLibraryContentsVersion()) { relPath = Well.reagents.restrict("libraryContentsVersion", _libraryContentsVersionRef.value()); } else { relPath = Well.latestReleasedReagent; } return relPath; } protected void buildCompoundPropertyColumns(List<TableColumn<Tuple<String>,?>> columns) { RelationshipPath<Well> relPath = getWellToReagentRelationshipPath(); final PropertyPath<Well> reagentIdPropertyPath = relPath.toProperty("id"); if (isLINCS()) { final PropertyPath<Well> facilityBatchIdPropertyPath = relPath.toProperty("facilityBatchId"); final PropertyPath<Well> saltFormIdPropertyPath = relPath.toProperty("saltFormId"); columns.add(new TextTupleColumn<Well,String>(PropertyPath.from(Well.class).toProperty("facilityId"), "Facility-Salt-Batch-ID", "the full Facility ID - SALT", COMPOUND_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { Object facilityIdValue = tuple.getProperty(TupleDataFetcher.makePropertyKey(getPropertyPath())); if (facilityIdValue != null) { return fsbColumnValueJoiner.join(facilityIdValue, NullSafeUtils.toString(tuple.getProperty(TupleDataFetcher.makePropertyKey(saltFormIdPropertyPath)), "?"), NullSafeUtils.toString(tuple.getProperty(TupleDataFetcher.makePropertyKey(facilityBatchIdPropertyPath)), "?")); } return null; } @Override public boolean isCommandLink() { return true; } @Override public Object cellAction(Tuple<String> tuple) { return viewSelectedEntity(); } });; ((TextTupleColumn) Iterables.getLast(columns)).addRelationshipPath(facilityBatchIdPropertyPath); ((TextTupleColumn) Iterables.getLast(columns)).addRelationshipPath(saltFormIdPropertyPath); columns.get(columns.size() - 1).setVisible(true); columns.add(new TextTupleColumn<Well,String>(relPath.toProperty("vendorBatchId"), "Vendor Batch Id", "Vendor assigned batch Id", COMPOUND_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextTupleColumn<Well,String>(reagentIdPropertyPath, "Primary Compound Name", "The primary compound name", COMPOUND_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { Integer reagentId = (Integer) tuple.getProperty(TupleDataFetcher.makePropertyKey(reagentIdPropertyPath)); if (reagentId != null) { SmallMoleculeReagent smallMoleculeReagent = _dao.findEntityById(SmallMoleculeReagent.class, reagentId, true, SmallMoleculeReagent.compoundNames); return smallMoleculeReagent.getPrimaryCompoundName(); } return null; } });; columns.get(columns.size() - 1).setVisible(true); } final PropertyPath<Well> restrictedStructurePropertyPath = relPath.toProperty("restrictedStructure"); columns.add(new ImageTupleColumn<Well,String>(reagentIdPropertyPath, "Compound Structure Image", "The structure image for the compound in the well", COMPOUND_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { if (_structureImageLocator != null) { Integer reagentId = (Integer) tuple.getProperty(TupleDataFetcher.makePropertyKey(reagentIdPropertyPath)); if (reagentId != null) { SmallMoleculeReagent smallMoleculeReagent = _dao.findEntityById(SmallMoleculeReagent.class, reagentId, true, Reagent.well.castToSubtype(SmallMoleculeReagent.class)); if(smallMoleculeReagent == null) return ""; // for [#3395] URL url = _structureImageLocator.getImageUrl(smallMoleculeReagent); return NullSafeUtils.toString(ImageLocatorUtil.toExtantContentUrl(url), ""); } } return null; } }); ((HasFetchPaths) Iterables.getLast(columns)).addRelationshipPath(restrictedStructurePropertyPath); Iterables.getLast(columns).setVisible(false); columns.add(new TextTupleColumn<Well,String>(relPath.toProperty("smiles"), "Compound SMILES", "The SMILES for the compound in the well", COMPOUND_COLUMNS_GROUP) { @Override public String getCellValue(final Tuple<String> tuple) { final String value = super.getCellValue(tuple); return ((SmallMoleculeReagent) new TuplePropertySmallMoleculeReagent(restrictedStructurePropertyPath, tuple) { @Override public String getSmiles() { return value; } }.restrict()).getSmiles(); } }); ((TextTupleColumn) Iterables.getLast(columns)).addRelationshipPath(restrictedStructurePropertyPath); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextTupleColumn<Well,String>(relPath.toProperty("inchi"), "Compound InChi", "The InChi for the compound in the well", COMPOUND_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { final String value = super.getCellValue(tuple); return ((SmallMoleculeReagent) new TuplePropertySmallMoleculeReagent(restrictedStructurePropertyPath, tuple) { @Override public String getInchi() { return value; } }.restrict()).getInchi(); } }); ((TextTupleColumn) Iterables.getLast(columns)).addRelationshipPath(restrictedStructurePropertyPath); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextTupleColumn<Well, String>(relPath .to(SmallMoleculeReagent.molecularFormula), "Molecular Formula", "The molecular formula for the compound in the well", COMPOUND_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { final String value = super.getCellValue(tuple); MolecularFormula v = ((SmallMoleculeReagent) new TuplePropertySmallMoleculeReagent( restrictedStructurePropertyPath, tuple) { @Override public MolecularFormula getMolecularFormula() { if(value!=null && value.length() > 0 && !"null".equalsIgnoreCase(value) ){ return new MolecularFormula(value); } return null; } }.restrict()).getMolecularFormula(); return v == null ? null : "" + v; } }); ((TextTupleColumn) Iterables.getLast(columns)) .addRelationshipPath(restrictedStructurePropertyPath); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextTupleColumn<Well, String>(relPath .to(SmallMoleculeReagent.molecularMass), "Molecular Mass", "The molecular mass for the compound in the well", COMPOUND_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { final String value = super.getCellValue(tuple); BigDecimal v = ((SmallMoleculeReagent) new TuplePropertySmallMoleculeReagent( restrictedStructurePropertyPath, tuple) { @Override public BigDecimal getMolecularMass() { if (value != null && value.length() > 0 && !"null".equalsIgnoreCase(value)) { return new BigDecimal(value); } return null; } }.restrict()).getMolecularMass(); return v == null ? null : "" + v; } }); ((TextTupleColumn) Iterables.getLast(columns)) .addRelationshipPath(restrictedStructurePropertyPath); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextTupleColumn<Well, String>(relPath .to(SmallMoleculeReagent.molecularWeight), "Molecular Weight", "The molecular weight for the compound in the well", COMPOUND_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { final String value = super.getCellValue(tuple); BigDecimal v = ((SmallMoleculeReagent) new TuplePropertySmallMoleculeReagent( restrictedStructurePropertyPath, tuple) { @Override public BigDecimal getMolecularWeight() { if(value!=null && value.length() > 0 && !"null".equalsIgnoreCase(value) ){ return new BigDecimal(value); } return null; } }.restrict()).getMolecularWeight(); return v == null ? null : "" + v; } }); ((TextTupleColumn) Iterables.getLast(columns)) .addRelationshipPath(restrictedStructurePropertyPath); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextSetTupleColumn<Well,String>(relPath.to(SmallMoleculeReagent.compoundNames), COLUMN_COMPOUND_NAMES, "The names of the compound in the well", COMPOUND_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new IntegerSetTupleColumn<Well,String>(relPath.to(SmallMoleculeReagent.pubchemCids), "PubChem CIDs", "The PubChem CIDs of the compound in the well", COMPOUND_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new IntegerSetTupleColumn<Well,String>(relPath.to(SmallMoleculeReagent.chembankIds), "ChemBank IDs", "The ChemBank IDs of the primary compound in the well", COMPOUND_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new IntegerSetTupleColumn<Well,String>(relPath.to(SmallMoleculeReagent.chemblIds), "CHEMBL IDs", "The CHEMBL IDs of the primary compound in the well", COMPOUND_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); } protected void buildReagentPropertyColumns(List<TableColumn<Tuple<String>,?>> columns) { RelationshipPath<Well> relPath = getWellToReagentRelationshipPath(); columns.add(new TextTupleColumn<Well,String>(relPath.to(Reagent.vendorName), "Reagent Vendor", "The vendor of the reagent in this well.", WELL_COLUMNS_GROUP)); columns.add(new TextTupleColumn<Well,String>(relPath.to(Reagent.vendorIdentifier), COLUMN_REAGENT_ID, "The vendor-assigned identifier for the reagent in this well.", WELL_COLUMNS_GROUP)); columns.add(new IntegerTupleColumn<Well,String>(relPath.to(Reagent.libraryContentsVersion).toProperty("versionNumber"), "Library Contents Version", "The reagent's library contents version", WELL_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); } protected void buildWellPropertyColumns(List<TableColumn<Tuple<String>,?>> columns) { columns.add(new IntegerTupleColumn<Well,String>(RelationshipPath.from(Well.class).toProperty("plateNumber"), "Plate", "The number of the plate the well is located on", WELL_COLUMNS_GROUP)); columns.add(new TextTupleColumn<Well,String>(RelationshipPath.from(Well.class).toProperty("wellName"), "Well", "The plate coordinates of the well", WELL_COLUMNS_GROUP) { @Override public boolean isCommandLink() { return true; } @Override public Object cellAction(Tuple<String> tuple) { return viewSelectedEntity(); } }); columns.add(new TextTupleColumn<Well,String>(Well.library.toProperty("libraryName"), "Library", "The library containing the well", WELL_COLUMNS_GROUP) { @Override public boolean isCommandLink() { return true; } @Override public Object cellAction(Tuple<String> tuple) { Well well = _dao.findEntityById(Well.class, tuple.getKey(), true, Well.library); return _libraryViewer.viewEntity(well.getLibrary()); } }); columns.add(new TextTupleColumn<Well,String>(Well.library.toProperty("provider"), "Provider", "The vendor or source that provided the library", WELL_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new EnumTupleColumn<Well,String,ScreenType>(Well.library.toProperty("screenType"), "Screen Type", "The library screen type", WELL_COLUMNS_GROUP, ScreenType.values())); columns.get(columns.size() - 1).setVisible(false); columns.add(new EnumTupleColumn<Well,String,LibraryWellType>(RelationshipPath.from(Well.class).toProperty("libraryWellType"), "Library Well Type", "The type of well, e.g., 'Experimental', 'Control', 'Empty', etc.", WELL_COLUMNS_GROUP, LibraryWellType.values())); if (isLINCS()) columns.get(columns.size() - 1).setVisible(false); columns.add(new TextTupleColumn<Well,String>(RelationshipPath.from(Well.class).toProperty("facilityId"), "Facility ID", "An alternate identifier assigned by the facility to identify this well", WELL_COLUMNS_GROUP) { @Override public boolean isCommandLink() { return isLINCS() && _mode == WellSearchResultMode.SET_OF_CANONICAL_REAGENT_WELLS; } @Override public Object cellAction(Tuple<String> row) { return viewSelectedEntity(); } }); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextTupleColumn<Well,String>(RelationshipPath.from(Well.class).toProperty("barcode"), "Barcode", "Barcode identifier for this well", WELL_COLUMNS_GROUP) { @Override public Object cellAction(Tuple<String> row) { return viewSelectedEntity(); } }); columns.get(columns.size() - 1).setVisible(false); columns.add(new BooleanTupleColumn<Well,String>(RelationshipPath.from(Well.class).toProperty("deprecated"), "Deprecated", "Whether the well has been deprecated", WELL_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); columns.add(new TextTupleColumn<Well,String>(Well.deprecationActivity.toProperty("comments"), "Deprecation Reason", "Why the well has been deprecated", WELL_COLUMNS_GROUP)); columns.get(columns.size() - 1).setVisible(false); // For [#3382] Library contents view should show the concentrations for the screening copies columns.add(new TextTupleColumn<Well, String>(RelationshipPath.from(Well.class).toProperty("molarConcentration"), "Screening Copy Concentration range (mg/mL)", "The mg/mL concentration of the screening copies", WELL_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { Well well = _dao.findEntityById(Well.class, tuple.getKey(), true, Well.library.to(Library.copies)); SortedSet<BigDecimal> values = getScreeningCopyConcentrations(well); if(values.isEmpty()) return null; else if (values.size() == 1) return values.first().toString(); else return values.first().toString() + "-" + values.last().toString(); } }); // TODO: unhide this column to finish [#3382] //Iterables.getLast(columns).setVisible(_mode != WellSearchResultMode.SCREEN_RESULT_WELLS); Iterables.getLast(columns).setVisible(false); columns.add(new TextTupleColumn<Well, String>(RelationshipPath.from(Well.class).toProperty("molarConcentration"), "Screening Copy Concentration range (molar)", "The molar concentration of the screening copies", WELL_COLUMNS_GROUP) { @Override public String getCellValue(Tuple<String> tuple) { Well well = _dao.findEntityById(Well.class, tuple.getKey(), true, Well.library.to(Library.copies)); SortedSet<MolarConcentration> values = getScreeningCopyMolarConcentrations(well); if(values.isEmpty()) return null; else if (values.size() == 1) return values.first().toString(); else return values.first().toString() + "-" + values.last().toString(); } }); // TODO: unhide this column to finish [#3382] //Iterables.getLast(columns).setVisible(_mode != WellSearchResultMode.SCREEN_RESULT_WELLS); Iterables.getLast(columns).setVisible(false); columns.add(new MolarConcentrationTupleColumn<Well,String>(RelationshipPath.from(Well.class).toProperty("molarConcentration"), "Molar Concentration", "The molar concentration of the library well", WELL_COLUMNS_GROUP)); Iterables.getLast(columns).setVisible(false); columns.add(new FixedDecimalTupleColumn<Well,String>(RelationshipPath.from(Well.class).toProperty("mgMlConcentration"), "mg/mL Concentration", "The mg/mL concentration of the library well", WELL_COLUMNS_GROUP)); Iterables.getLast(columns).setVisible(false); } private Map<Library,Set<BigDecimal>> screeningCopyDilutionFactors; // cache private Set<BigDecimal> getScreeningCopyDilutions(Library l) { if(screeningCopyDilutionFactors == null) { screeningCopyDilutionFactors = Maps.newHashMap(); } if(!screeningCopyDilutionFactors.containsKey(l)) { Set<BigDecimal> values = Sets.newHashSet(); for(Copy c:l.getCopies()) { if(c.getUsageType() == CopyUsageType.LIBRARY_SCREENING_PLATES) { values.add(c.getWellConcentrationDilutionFactor()); } } screeningCopyDilutionFactors.put(l, values); } return screeningCopyDilutionFactors.get(l); } private SortedSet<BigDecimal> getScreeningCopyConcentrations(Well w) { SortedSet<BigDecimal> values = Sets.newTreeSet(); for(BigDecimal df:getScreeningCopyDilutions(w.getLibrary())){ if(w.getMgMlConcentration() != null) values.add(w.getMgMlConcentration().divide(df,ScreensaverConstants.PLATE_DILUTION_FACTOR_SCALE, RoundingMode.HALF_UP)); } return values; } private SortedSet<MolarConcentration> getScreeningCopyMolarConcentrations(Well w) { SortedSet<MolarConcentration> values = Sets.newTreeSet(); for (BigDecimal df : getScreeningCopyDilutions(w.getLibrary())) { if (w.getMolarConcentration() != null) { BigDecimal value = w.getMolarConcentration().getValue() .divide(df, ScreensaverConstants.PLATE_DILUTION_FACTOR_SCALE, RoundingMode.HALF_UP); values.add(MolarConcentration.makeConcentration(value.toString(), w.getMolarConcentration().getUnits(), RoundingMode.HALF_UP)); } } return values; } protected void buildDataColumns(List<TableColumn<Tuple<String>,?>> columns, List<DataColumn> dataColumns) { List<TableColumn<Tuple<String>,?>> otherColumns = Lists.newArrayList(); boolean areAssayWellColumnsCreated = false; for (final DataColumn dataColumn : dataColumns) { if (dataColumn.isRestricted()) { continue; } String screenFacilityId = dataColumn.getScreenResult().getScreen().getFacilityId(); String screenTitle = dataColumn.getScreenResult().getScreen().getTitle(); TableColumn<Tuple<String>,?> column; if (dataColumn.isPartitionPositiveIndicator()) { column = new EnumTupleColumn<Well,String,PartitionedValue>(Well.resultValues.restrict(ResultValue.DataColumn.getLeaf(), dataColumn).toProperty("partitionedPositiveValue"), makeColumnName(dataColumn, screenFacilityId), makeColumnDescription(dataColumn, screenFacilityId, screenTitle, dataColumn.getDataType()), makeScreenColumnGroup(screenFacilityId, screenTitle), PartitionedValue.values()); } else if (dataColumn.isBooleanPositiveIndicator()) { column = new BooleanTupleColumn<Well,String>(Well.resultValues.restrict(ResultValue.DataColumn.getLeaf(), dataColumn).toProperty("booleanPositiveValue"), makeColumnName(dataColumn, screenFacilityId), makeColumnDescription(dataColumn, screenFacilityId, screenTitle, dataColumn.getDataType()), makeScreenColumnGroup(screenFacilityId, screenTitle)); } else if (dataColumn.isConfirmedPositiveIndicator()) { column = new EnumTupleColumn<Well,String,ConfirmedPositiveValue>(Well.resultValues.restrict(ResultValue.DataColumn.getLeaf(), dataColumn).toProperty("confirmedPositiveValue"), makeColumnName(dataColumn, screenFacilityId), makeColumnDescription(dataColumn, screenFacilityId, screenTitle, dataColumn.getDataType()), makeScreenColumnGroup(screenFacilityId, screenTitle), ConfirmedPositiveValue.values()); } else if (dataColumn.isNumeric()) { column = new RealTupleColumn<Well,String>(Well.resultValues.restrict(ResultValue.DataColumn.getLeaf(), dataColumn).toProperty("numericValue"), makeColumnName(dataColumn, screenFacilityId), makeColumnDescription(dataColumn, screenFacilityId, screenTitle, dataColumn.getDataType()), makeScreenColumnGroup(screenFacilityId, screenTitle), dataColumn.getDecimalPlaces()); } else { column = new TextTupleColumn<Well,String>(Well.resultValues.restrict(ResultValue.DataColumn.getLeaf(), dataColumn).toProperty("value"), makeColumnName(dataColumn, screenFacilityId), makeColumnDescription(dataColumn, screenFacilityId, screenTitle, dataColumn.getDataType()), makeScreenColumnGroup(screenFacilityId, screenTitle)); } column = new ViewPolicyAwareResultValueColumn<Tuple<String>,Object>((TableColumn<Tuple<String>,Object>) column, dataColumn) { private String _positivePropertyKey; @Override protected boolean isResultValueRestricted(Tuple<String> tuple) { if (_entityViewPolicy.isAllowedAccessToDataColumnDueToMutualPositives(dataColumn)) { // only perform result value visibility checks if we're dealing with the special case of a data column that reveals only the subset of mutual positive wells Boolean isPositive = (Boolean) tuple.getProperty(_positivePropertyKey); return !!!_entityViewPolicy.isAllowedAccessToResultValueDueToMutualPositive(isPositive == null ? false : isPositive.booleanValue(), dataColumn.getScreenResult().getScreen(), tuple.getKey()); } else { assert _entityViewPolicy.visit(dataColumn) != null; return false; } } @Override protected void initialize() { if (_entityViewPolicy.isAllowedAccessToDataColumnDueToMutualPositives(dataColumn)) { PropertyPath<ResultValue> positiveProperty = getPropertyPath().getAncestryPath().toProperty("positive"); _positivePropertyKey = TupleDataFetcher.makePropertyKey(positiveProperty); addRelationshipPath(positiveProperty); if (log.isDebugEnabled()) { log.debug("adding fetch path for ResultValue.isPositive, to calculate visibility of mutual positives for table column " + getName()); } } } }; // request eager fetching of dataColumn, since Hibernate will otherwise fetch these with individual SELECTs // we also need to eager fetch all the way "up" to Screen, for data access policy checks //((HasFetchPaths<Well>) column).addRelationshipPath(Well.resultValues.to(ResultValue.DataColumn).to(DataColumn.ScreenResult).to(ScreenResult.screen)); if (!areAssayWellColumnsCreated && column.getGroup().equals(OUR_DATA_COLUMNS_GROUP)) { columns.add(new EnumTupleColumn<Well,String,AssayWellControlType>(Well.resultValues.restrict(ResultValue.DataColumn.getLeaf(), dataColumn).toProperty("assayWellControlType"), "Assay Well Control Type", "The type of assay well control", ASSAY_DESCRIPTORS_COLUMNS_GROUP, AssayWellControlType.values())); if (isLINCS()) { final LibraryScreening libraryScreening = getLibraryScreening(); if (libraryScreening != null && _mode == WellSearchResultMode.SCREEN_RESULT_WELLS) { columns.add(new TableColumn<Tuple<String>,Volume>("Assay Well Volume", "The volume of the assay in the assay well, before transferring a volume of the library compound", ColumnType.VOLUME, ASSAY_DESCRIPTORS_COLUMNS_GROUP) { @Override public Volume getCellValue(Tuple<String> tuple) { return libraryScreening.getAssayWellVolume(); } @Override public boolean isSortableSearchable() { return false; } }); columns.get(columns.size() - 1).setVisible(false); // TODO: determine the visibility for this column columns.add(new TableColumn<Tuple<String>,Volume>("Volume Transferred per Well", "The volume of library compound transferred to the assay well", ColumnType.VOLUME, ASSAY_DESCRIPTORS_COLUMNS_GROUP) { @Override public Volume getCellValue(Tuple<String> tuple) { return libraryScreening.getVolumeTransferredPerWellToAssayPlates(); } @Override public boolean isSortableSearchable() { return false; } }); columns.get(columns.size() - 1).setVisible(false); columns.add(new TableColumn<Tuple<String>,Volume>("Final Assay Well Volume", "The sum of the assay well volume and the volume of library compound transferred to the assay well", ColumnType.VOLUME, ASSAY_DESCRIPTORS_COLUMNS_GROUP) { @Override public Volume getCellValue(Tuple<String> tuple) { return libraryScreening.getVolumeTransferredPerWellToAssayPlates().add(libraryScreening.getAssayWellVolume()); } @Override public boolean isSortableSearchable() { return false; } }); columns.get(columns.size() - 1).setVisible(false); columns.add(new MolarConcentrationTupleColumn<Well,String>(RelationshipPath.from(Well.class).toProperty("molarConcentration"), "Assay Well Concentration", "The molar concentration of the library compound in the assay well", ASSAY_DESCRIPTORS_COLUMNS_GROUP) { @Override public MolarConcentration getCellValue(Tuple<String> tuple) { // TODO: don't show if well.type != experimental MolarConcentration libraryWellConcentration = super.getCellValue(tuple); Volume volumeXferred = libraryScreening.getVolumeTransferredPerWellToAssayPlates(); if (libraryWellConcentration == null || volumeXferred == null || libraryScreening.getAssayWellVolume() == null) return null; Volume finalAssayVolume = volumeXferred.add(libraryScreening.getAssayWellVolume()); BigDecimal dilutionFactor = volumeXferred.getValue().divide(finalAssayVolume.getValue(), 4, RoundingMode.HALF_EVEN); return MolarConcentration.makeConcentration(libraryWellConcentration.getValue().multiply(dilutionFactor).toPlainString(), libraryWellConcentration.getUnits(), RoundingMode.HALF_UP); } @Override public boolean isSortableSearchable() { return false; } }); } } areAssayWellColumnsCreated = true; } if (column.getGroup().equals(OUR_DATA_COLUMNS_GROUP)) { columns.add(column); column.setVisible(true); } else { otherColumns.add(column); column.setVisible(false); } } columns.addAll(otherColumns); } protected LibraryScreening getLibraryScreening() { if (_screenResult == null) return null; SortedSet<? extends LabActivity> temp = _screenResult.getScreen().getLabActivitiesOfType(LibraryScreening.class); return temp.isEmpty() ? null : (LibraryScreening) temp.last(); } protected String makeScreenColumnGroup(String facilityId, String screenTitle) { String columnGroup; if (_screenResult != null && _screenResult.getScreen().getFacilityId().equals(facilityId)) { columnGroup = OUR_DATA_COLUMNS_GROUP; } else { columnGroup = OTHER_DATA_COLUMNS_GROUP + TableColumnManager.GROUP_NODE_DELIMITER + facilityId + " (" + screenTitle + ")"; } return columnGroup; } protected String makeStudyColumnGroup(String facilityId, String studyTitle) { String columnGroup; if (_study != null && facilityId.equals(_study.getFacilityId())) { columnGroup = OUR_ANNOTATION_TYPES_COLUMN_GROUP; } else { columnGroup = OTHER_ANNOTATION_TYPES_COLUMN_GROUP + TableColumnManager.GROUP_NODE_DELIMITER + facilityId + " (" + studyTitle + ")"; } return columnGroup; } protected List<DataColumn> findValidDataColumns() { return _dao.runQuery(new Query() { public List<DataColumn> execute(Session session) { HqlBuilder hql = new HqlBuilder(); hql.distinctProjectionValues(). select("dc"). from(DataColumn.class, "dc"). from("dc", DataColumn.ScreenResult, "sr", JoinType.LEFT_FETCH). from("sr", ScreenResult.screen, "s", JoinType.LEFT_FETCH). whereIn("s", "screenType", _screenTypes). orderBy("s", Screen.facilityId.getPropertyName()).orderBy("dc", "ordinal"); if (log.isDebugEnabled()) { log.debug("findValidDataColumns query: " + hql.toHql()); } Iterable<DataColumn> dataColumns = hql.toQuery(session, true).list(); return Lists.newArrayList(Iterables.filter(dataColumns, Entity.NotRestricted)); } }); } protected List<AnnotationType> findValidAnnotationTypes() { if(_validAnnotationTypes == null) { log.info("entering findValidAnnotationTypes"); _validAnnotationTypes = _dao.runQuery(new Query() { public List<AnnotationType> execute(Session session) { HqlBuilder hql = new HqlBuilder(); hql.select("at").distinctProjectionValues(). from(AnnotationType.class, "at").from("at", AnnotationType.study, "s", JoinType.LEFT_FETCH). whereIn("s", "screenType", _screenTypes). orderBy("s", Screen.facilityId.getPropertyName()).orderBy("at", "ordinal"); if (log.isDebugEnabled()) { log.debug("findValidAnnotationTypes query: " + hql.toHql()); } Iterable<AnnotationType> annotTypes = hql.toQuery(session, true).list(); return Lists.newArrayList(Iterables.filter(annotTypes, Entity.NotRestricted)); } }); } return _validAnnotationTypes; } protected void buildAnnotationTypeColumns(List<TableColumn<Tuple<String>,?>> columns) { List<TableColumn<Tuple<String>,?>> otherColumns = Lists.newArrayList(); for (final AnnotationType annotationType : findValidAnnotationTypes()) { String studyId = annotationType.getStudy().getFacilityId(); String studyTitle = annotationType.getStudy().getTitle(); TableColumn<Tuple<String>,?> column; String columnGroup = makeStudyColumnGroup(studyId, studyTitle); if (annotationType.isNumeric()) { // TODO: find appropriate version of reagent column = new RealTupleColumn<Well,String>(Well.latestReleasedReagent.to(Reagent.annotationValues).restrict(AnnotationValue.annotationType.getLeaf(), annotationType).toProperty("numericValue"), makeColumnName(annotationType, studyId), WellSearchResults.makeColumnDescription(annotationType, studyId, studyTitle, DataType.NUMERIC), columnGroup, -1); } else { column = new TextTupleColumn<Well,String>(Well.latestReleasedReagent.to(Reagent.annotationValues).restrict(AnnotationValue.annotationType.getLeaf(), annotationType).toProperty("value"), makeColumnName(annotationType, studyId), WellSearchResults.makeColumnDescription(annotationType, studyId, studyTitle, DataType.TEXT), columnGroup); } if (column.getName().equals(OUR_ANNOTATION_TYPES_COLUMN_GROUP)) { columns.add(column); column.setVisible(true); } else { otherColumns.add(column); column.setVisible(false); } } columns.addAll(otherColumns); } public static String makeColumnName(MetaDataType mdt, String parentIdentifier) { // note: replacing "_" with white space allows column name labels to wrap, creating narrower columns return String.format("%s [%s]", mdt.getName().replaceAll("_", " "), parentIdentifier); } static String makeColumnDescription(MetaDataType mdt, String parentIdentifier, String parentTitle, DataType dataType) { return makeColumnDescription(mdt.getName(), mdt.getDescription(), parentIdentifier, parentTitle, dataType); } static String makeColumnDescription(String name, String description, String parentIdentifier, String parentTitle, DataType dataType) { StringBuilder columnDescription = new StringBuilder(); columnDescription.append("<i>").append(parentIdentifier).append(": ").append(parentTitle). append("</i><br/><b>").append(name).append("</b>"); if (description != null) { columnDescription.append(": ").append(description); } switch (dataType) { case POSITIVE_INDICATOR_PARTITION: columnDescription.append("<div class=\"positivesDataColumnLegend\">Legend:<br/>S=Strong<br/>M=Medium<br/>W=Weak<br/>NP=Not a positive<br/>blank=No data</div>"); break; case POSITIVE_INDICATOR_BOOLEAN: columnDescription.append("<div class=\"positivesDataColumnLegend\">Legend:<br/>true=Positive<br/>false=Not a positive<br/>blank=No data</div>"); break; case CONFIRMED_POSITIVE_INDICATOR: columnDescription.append("<div class=\"positivesDataColumnLegend\">Legend:<br/>true=Confirmed positive<br/>false=Not a confirmed positive<br/>blank=No data</div>"); break; } return columnDescription.toString(); } // protected void setLINCS(boolean isLINCS) // { // _isLINCS = isLINCS; // } // // protected boolean isLINCS() // { // if (_isLINCS == null) { // _isLINCS = getApplicationProperties().isFacility(LincsScreensaverConstants.FACILITY_KEY); // } // return _isLINCS; // } protected boolean accessSpecificLibraryContentsVersion() { return _mode == WellSearchResultMode.LIBRARY_WELLS && _libraryContentsVersionRef.value() != null; } }