Java tutorial
/* * The Gemma project. * * Copyright (c) 2006 University of British Columbia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package ubic.gemma.persistence.service.expression.experiment; import com.google.common.base.Strings; import gemma.gsec.SecurityService; import org.apache.commons.math3.exception.NotStrictlyPositiveException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ubic.gemma.core.analysis.preprocess.batcheffects.BatchConfound; import ubic.gemma.core.analysis.preprocess.batcheffects.BatchConfoundValueObject; import ubic.gemma.core.analysis.preprocess.batcheffects.BatchEffectDetails; import ubic.gemma.core.analysis.preprocess.batcheffects.BatchInfoPopulationServiceImpl; import ubic.gemma.core.analysis.preprocess.svd.SVDService; import ubic.gemma.core.analysis.preprocess.svd.SVDValueObject; import ubic.gemma.core.ontology.OntologyService; import ubic.gemma.core.search.SearchResult; import ubic.gemma.core.search.SearchService; import ubic.gemma.model.analysis.expression.ExpressionExperimentSet; import ubic.gemma.model.common.auditAndSecurity.AuditEvent; import ubic.gemma.model.common.auditAndSecurity.eventType.AuditEventType; import ubic.gemma.model.common.auditAndSecurity.eventType.LinkAnalysisEvent; import ubic.gemma.model.common.auditAndSecurity.eventType.MissingValueAnalysisEvent; import ubic.gemma.model.common.auditAndSecurity.eventType.ProcessedVectorComputationEvent; import ubic.gemma.model.common.description.AnnotationValueObject; import ubic.gemma.model.common.description.BibliographicReference; import ubic.gemma.model.common.description.Characteristic; import ubic.gemma.model.common.description.DatabaseEntry; import ubic.gemma.model.common.quantitationtype.QuantitationType; import ubic.gemma.model.common.search.SearchSettingsImpl; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; import ubic.gemma.model.expression.arrayDesign.TechnologyType; import ubic.gemma.model.expression.bioAssay.BioAssay; import ubic.gemma.model.expression.bioAssayData.BioAssayDimension; import ubic.gemma.model.expression.bioAssayData.RawExpressionDataVector; import ubic.gemma.model.expression.biomaterial.BioMaterial; import ubic.gemma.model.expression.experiment.*; import ubic.gemma.model.genome.Gene; import ubic.gemma.model.genome.Taxon; import ubic.gemma.persistence.service.AbstractService; import ubic.gemma.persistence.service.AbstractVoEnabledService; import ubic.gemma.persistence.service.analysis.expression.coexpression.CoexpressionAnalysisService; import ubic.gemma.persistence.service.analysis.expression.diff.DifferentialExpressionAnalysisService; import ubic.gemma.persistence.service.analysis.expression.pca.PrincipalComponentAnalysisService; import ubic.gemma.persistence.service.analysis.expression.sampleCoexpression.SampleCoexpressionAnalysisService; import ubic.gemma.persistence.service.common.auditAndSecurity.AuditEventDao; import ubic.gemma.persistence.service.common.quantitationtype.QuantitationTypeService; import ubic.gemma.persistence.service.expression.bioAssayData.BioAssayDimensionService; import ubic.gemma.persistence.service.expression.bioAssayData.ProcessedExpressionDataVectorService; import ubic.gemma.persistence.service.expression.bioAssayData.RawExpressionDataVectorDao; import ubic.gemma.persistence.util.ObjectFilter; import java.util.*; /** * @author pavlidis * @author keshav * @see ExpressionExperimentService */ @Service @Transactional public class ExpressionExperimentServiceImpl extends AbstractVoEnabledService<ExpressionExperiment, ExpressionExperimentValueObject> implements ExpressionExperimentService { private static final double BATCH_CONFOUND_THRESHOLD = 0.01; private static final double BATCH_EFFECT_THRESHOLD = 0.01; private final ExpressionExperimentDao expressionExperimentDao; @Autowired private AuditEventDao auditEventDao; @Autowired private BioAssayDimensionService bioAssayDimensionService; @Autowired private DifferentialExpressionAnalysisService differentialExpressionAnalysisService; @Autowired private ExpressionExperimentSetService expressionExperimentSetService; @Autowired private ExpressionExperimentSubSetService expressionExperimentSubSetService; @Autowired private ExperimentalFactorDao experimentalFactorDao; @Autowired private FactorValueDao factorValueDao; @Autowired private RawExpressionDataVectorDao rawExpressionDataVectorDao; @Autowired private OntologyService ontologyService; @Autowired private PrincipalComponentAnalysisService principalComponentAnalysisService; @Autowired private ProcessedExpressionDataVectorService processedVectorService; @Autowired private QuantitationTypeService quantitationTypeDao; @Autowired private SearchService searchService; @Autowired private SecurityService securityService; @Autowired private SVDService svdService; @Autowired private CoexpressionAnalysisService coexpressionAnalysisService; @Autowired private SampleCoexpressionAnalysisService sampleCoexpressionAnalysisService; @Autowired private BlacklistedEntityDao blacklistedEntityDao; @Autowired public ExpressionExperimentServiceImpl(ExpressionExperimentDao expressionExperimentDao) { super(expressionExperimentDao); this.expressionExperimentDao = expressionExperimentDao; } @Override @Transactional public ExperimentalFactor addFactor(ExpressionExperiment ee, ExperimentalFactor factor) { ExpressionExperiment experiment = expressionExperimentDao.load(ee.getId()); factor.setExperimentalDesign(experiment.getExperimentalDesign()); factor.setSecurityOwner(experiment); factor = experimentalFactorDao.create(factor); // to make sure we get acls. experiment.getExperimentalDesign().getExperimentalFactors().add(factor); expressionExperimentDao.update(experiment); return factor; } @Override @Transactional public void addFactorValue(ExpressionExperiment ee, FactorValue fv) { assert fv.getExperimentalFactor() != null; ExpressionExperiment experiment = expressionExperimentDao.load(ee.getId()); fv.setSecurityOwner(experiment); Collection<ExperimentalFactor> efs = experiment.getExperimentalDesign().getExperimentalFactors(); fv = this.factorValueDao.create(fv); for (ExperimentalFactor ef : efs) { if (fv.getExperimentalFactor().equals(ef)) { ef.getFactorValues().add(fv); break; } } expressionExperimentDao.update(experiment); } @Override @Transactional public ExpressionExperiment addRawVectors(ExpressionExperiment ee, Collection<RawExpressionDataVector> newVectors) { Collection<BioAssayDimension> BADs = new HashSet<>(); Collection<QuantitationType> qts = new HashSet<>(); for (RawExpressionDataVector vec : newVectors) { BADs.add(vec.getBioAssayDimension()); qts.add(vec.getQuantitationType()); } if (BADs.size() > 1) { throw new IllegalArgumentException("Vectors must share a common bioassay dimension"); } if (qts.size() > 1) { throw new UnsupportedOperationException( "Can only replace with one type of vector (only one quantitation type)"); } BioAssayDimension bad = BADs.iterator().next(); if (bad.getId() == null) { bad = this.bioAssayDimensionService.findOrCreate(bad); } assert bad.getBioAssays().size() > 0; QuantitationType newQt = qts.iterator().next(); if (newQt.getId() == null) { newQt = this.quantitationTypeDao.create(newQt); } else { AbstractService.log.warn("Quantitation type already had an ID...:" + newQt); } /* * This is probably a more or less redundant setting, but doesn't hurt to make sure. */ ArrayDesign vectorAd = newVectors.iterator().next().getDesignElement().getArrayDesign(); for (BioAssay ba : bad.getBioAssays()) { ba.setArrayDesignUsed(vectorAd); } for (RawExpressionDataVector vec : newVectors) { vec.setBioAssayDimension(bad); vec.setQuantitationType(newQt); } ee = rawExpressionDataVectorDao.addVectors(ee.getId(), newVectors); // FIXME should be able to just do ee.getRawExpressionDataVectors.addAll(newVectors) // this is a denormalization; easy to forget to update this. ee.getQuantitationTypes().add(newQt); AbstractService.log.info(ee.getRawExpressionDataVectors().size() + " vectors for experiment"); return ee; } @Override @Transactional(readOnly = true) public List<ExpressionExperiment> browse(Integer start, Integer limit) { return this.expressionExperimentDao.browse(start, limit); } @Override public boolean checkHasBatchInfo(ExpressionExperiment ee) { boolean hasBatchInformation = false; for (ExperimentalFactor ef : ee.getExperimentalDesign().getExperimentalFactors()) { if (BatchInfoPopulationServiceImpl.isBatchFactor(ef)) { hasBatchInformation = true; break; } } if (!hasBatchInformation) { boolean allBAsHaveDate = true; ee = this.thawBioAssays(ee); for (BioAssay ba : ee.getBioAssays()) { if (ba.getProcessingDate() == null) { allBAsHaveDate = false; break; } } if (allBAsHaveDate) { hasBatchInformation = true; } } return hasBatchInformation; } @Override public Integer countNotTroubled() { return this.expressionExperimentDao.countNotTroubled(); } /** * returns ids of search results * * @return collection of ids or an empty collection */ @Override @Transactional(readOnly = true) public Collection<Long> filter(String searchString) { Map<Class<?>, List<SearchResult>> searchResultsMap = searchService .search(SearchSettingsImpl.expressionExperimentSearch(searchString)); assert searchResultsMap != null; Collection<SearchResult> searchResults = searchResultsMap.get(ExpressionExperiment.class); Collection<Long> ids = new ArrayList<>(searchResults.size()); for (SearchResult s : searchResults) { ids.add(s.getId()); } return ids; } @Override public Collection<Long> filterByTaxon(Collection<Long> ids, Taxon taxon) { return this.expressionExperimentDao.filterByTaxon(ids, taxon); } /** * @see ExpressionExperimentService#findByAccession(DatabaseEntry) */ @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> findByAccession(final DatabaseEntry accession) { return this.expressionExperimentDao.findByAccession(accession); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> findByAccession(String accession) { return this.expressionExperimentDao.findByAccession(accession); } /** * @see ExpressionExperimentService#findByBibliographicReference(BibliographicReference) */ @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> findByBibliographicReference(final BibliographicReference bibRef) { return this.expressionExperimentDao.findByBibliographicReference(bibRef.getId()); } /** * @see ExpressionExperimentService#findByBioAssay(BioAssay) */ @Override @Transactional(readOnly = true) public ExpressionExperiment findByBioAssay(final BioAssay ba) { return this.expressionExperimentDao.findByBioAssay(ba); } /** * @see ExpressionExperimentService#findByBioMaterial(BioMaterial) */ @Override @Transactional(readOnly = true) public ExpressionExperiment findByBioMaterial(final BioMaterial bm) { return this.expressionExperimentDao.findByBioMaterial(bm); } /** * @see ExpressionExperimentService#findByBioMaterials(Collection) */ @Override @Transactional(readOnly = true) public Map<ExpressionExperiment, BioMaterial> findByBioMaterials(final Collection<BioMaterial> bioMaterials) { return this.expressionExperimentDao.findByBioMaterials(bioMaterials); } /** * @see ExpressionExperimentService#findByExpressedGene(Gene, double) */ @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> findByExpressedGene(final Gene gene, final double rank) { return this.expressionExperimentDao.findByExpressedGene(gene, rank); } /** * @see ExpressionExperimentService#findByFactor(ExperimentalFactor) */ @Override @Transactional(readOnly = true) public ExpressionExperiment findByFactor(final ExperimentalFactor factor) { return this.expressionExperimentDao.findByFactor(factor); } /** * @see ExpressionExperimentService#findByFactorValue(FactorValue) */ @Override @Transactional(readOnly = true) public ExpressionExperiment findByFactorValue(final FactorValue factorValue) { return this.expressionExperimentDao.findByFactorValue(factorValue); } /** * @see ExpressionExperimentService#findByFactorValue(FactorValue) */ @Override @Transactional(readOnly = true) public ExpressionExperiment findByFactorValue(final Long factorValueId) { return this.expressionExperimentDao.findByFactorValue(factorValueId); } /** * @see ExpressionExperimentService#findByFactorValues(Collection) */ @Override @Transactional(readOnly = true) public Map<ExpressionExperiment, FactorValue> findByFactorValues(final Collection<FactorValue> factorValues) { return this.expressionExperimentDao.findByFactorValues(factorValues); } /** * @see ExpressionExperimentService#findByGene(Gene) */ @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> findByGene(final Gene gene) { return this.expressionExperimentDao.findByGene(gene); } /** * @see ExpressionExperimentService#findByName(String) */ @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> findByName(final String name) { return this.expressionExperimentDao.findByName(name); } @Override @Transactional(readOnly = true) public ExpressionExperiment findByQuantitationType(QuantitationType type) { return this.expressionExperimentDao.findByQuantitationType(type); } /** * @see ExpressionExperimentService#findByShortName(String) */ @Override @Transactional(readOnly = true) public ExpressionExperiment findByShortName(final String shortName) { return this.expressionExperimentDao.findByShortName(shortName); } /** * @see ExpressionExperimentService#findByTaxon(Taxon) */ @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> findByTaxon(final Taxon taxon) { return this.expressionExperimentDao.findByTaxon(taxon); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> findByTaxon(final Taxon taxon, Integer limit) { return this.expressionExperimentDao.findByTaxon(taxon, limit); } @Override @Transactional(readOnly = true) public List<ExpressionExperiment> findByUpdatedLimit(Integer limit) { return this.expressionExperimentDao.findByUpdatedLimit(limit); } @Override public Collection<ExpressionExperiment> findUpdatedAfter(Date date) { return this.expressionExperimentDao.findUpdatedAfter(date); } @Override @Transactional(readOnly = true) public Map<Long, Integer> getAnnotationCounts(final Collection<Long> ids) { return this.expressionExperimentDao.getAnnotationCounts(ids); } @Override @Transactional(readOnly = true) public Collection<AnnotationValueObject> getAnnotations(Long eeId) { ExpressionExperiment expressionExperiment = this.load(eeId); Collection<AnnotationValueObject> annotations = new HashSet<>(); Collection<String> seenTerms = new HashSet<>(); for (Characteristic c : expressionExperiment.getCharacteristics()) { AnnotationValueObject annotationValue = new AnnotationValueObject(); annotationValue.setId(c.getId()); annotationValue.setClassName(c.getCategory()); annotationValue.setClassUri(c.getCategoryUri()); annotationValue.setTermName(c.getValue()); annotationValue.setTermUri(c.getValueUri()); annotationValue.setEvidenceCode(c.getEvidenceCode() != null ? c.getEvidenceCode().toString() : ""); annotationValue.setObjectClass("ExperimentTag"); annotations.add(annotationValue); seenTerms.add(annotationValue.getTermName()); } /* * TODO If can be done without much slowdown, add: certain selected (constant?) characteristics from * biomaterials? (non-redundant with tags) */ for (AnnotationValueObject v : this.getAnnotationsByBioMaterials(eeId)) { if (!seenTerms.contains(v.getTermName())) { annotations.add(v); } seenTerms.add(v.getTermName()); } /* * TODO If can be done without much slowdown, add: certain characteristics from factor values? (non-baseline, * non-batch, non-redundant with tags). This is tricky because they are so specific... */ for (AnnotationValueObject v : this.getAnnotationsByFactorValues(eeId)) { if (!seenTerms.contains(v.getTermName())) { annotations.add(v); } seenTerms.add(v.getTermName()); } return annotations; } @Override @Transactional(readOnly = true) public Collection<ArrayDesign> getArrayDesignsUsed(final BioAssaySet expressionExperiment) { return this.expressionExperimentDao.getArrayDesignsUsed(expressionExperiment); } @Override @Transactional(readOnly = true) public String getBatchConfound(ExpressionExperiment ee) { ee = this.thawBioAssays(ee); if (!this.checkHasBatchInfo(ee)) { return null; } Collection<BatchConfoundValueObject> confounds; try { confounds = BatchConfound.test(ee); } catch (NotStrictlyPositiveException e) { AbstractService.log.error("Batch confound test threw a NonStrictlyPositiveException! Returning null."); return null; } StringBuilder result = new StringBuilder(); // Confounds have to be sorted in order to always get the same string List<BatchConfoundValueObject> listConfounds = new ArrayList<>(confounds); Collections.sort(listConfounds, new Comparator<BatchConfoundValueObject>() { @Override public int compare(BatchConfoundValueObject t0, BatchConfoundValueObject t1) { return t0.toString().compareTo(t1.toString()); } }); for (BatchConfoundValueObject c : listConfounds) { if (c.getP() < ExpressionExperimentServiceImpl.BATCH_CONFOUND_THRESHOLD) { String factorName = c.getEf().getName(); if (!result.toString().isEmpty()) { result.append(", "); } result.append("Factor '").append(factorName).append("' may be confounded with batches; p=") .append(String.format("%.2g", c.getP())); } } return Strings.emptyToNull(result.toString()); } @Override @Transactional(readOnly = true) public BatchEffectDetails getBatchEffect(ExpressionExperiment ee) { ee = this.thawLiter(ee); BatchEffectDetails details = new BatchEffectDetails(this.checkHasBatchInfo(ee), this.getHasBeenBatchCorrected(ee)); if (details.hasNoBatchInfo()) return details; for (ExperimentalFactor ef : ee.getExperimentalDesign().getExperimentalFactors()) { if (BatchInfoPopulationServiceImpl.isBatchFactor(ef)) { SVDValueObject svd = svdService.getSvdFactorAnalysis(ee.getId()); if (svd == null) break; double minP = 1.0; for (Integer component : svd.getFactorPvals().keySet()) { Map<Long, Double> cmpEffects = svd.getFactorPvals().get(component); Double pVal = cmpEffects.get(ef.getId()); if (pVal != null && pVal < minP) { details.setPvalue(pVal); details.setComponent(component + 1); details.setComponentVarianceProportion(svd.getVariances()[component]); minP = pVal; } } return details; } } return details; } @Override @Transactional(readOnly = true) public String getBatchEffectDescription(ExpressionExperiment ee) { BatchEffectDetails beDetails = this.getBatchEffect(ee); String result = ""; if (beDetails != null && !beDetails.hasNoBatchInfo()) { if (beDetails.getDataWasBatchCorrected()) { result = "Data has been batch-corrected"; // Checked for in ExpressionExperimentDetails.js::renderStatus() } else if (beDetails.getPvalue() < ExpressionExperimentServiceImpl.BATCH_EFFECT_THRESHOLD) { String pc = beDetails.getComponent() != null ? " (PC " + beDetails.getComponent() + ")" : ""; result = "This data set may have a batch artifact" + pc + ", p=" + String.format("%.5g", beDetails.getPvalue()); } else { result = "No batch effect was detected"; } } return Strings.emptyToNull(result); } @Override @Transactional(readOnly = true) public Collection<BioAssayDimension> getBioAssayDimensions(ExpressionExperiment expressionExperiment) { Collection<BioAssayDimension> bioAssayDimensions = this.expressionExperimentDao .getBioAssayDimensions(expressionExperiment); Collection<BioAssayDimension> thawedBioAssayDimensions = new HashSet<>(); for (BioAssayDimension bioAssayDimension : bioAssayDimensions) { thawedBioAssayDimensions.add(this.bioAssayDimensionService.thaw(bioAssayDimension)); } return thawedBioAssayDimensions; } @Override @Transactional(readOnly = true) public Integer getBioMaterialCount(final ExpressionExperiment expressionExperiment) { return this.expressionExperimentDao.getBioMaterialCount(expressionExperiment); } @Override @Transactional(readOnly = true) public Integer getDesignElementDataVectorCountById(final Long id) { return this.expressionExperimentDao.getDesignElementDataVectorCountById(id); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> getExperimentsWithOutliers() { return this.expressionExperimentDao.getExperimentsWithOutliers(); } @Override @Transactional(readOnly = true) public Map<Long, Date> getLastArrayDesignUpdate(final Collection<ExpressionExperiment> expressionExperiments) { return this.expressionExperimentDao.getLastArrayDesignUpdate(expressionExperiments); } @Override @Transactional(readOnly = true) public Date getLastArrayDesignUpdate(final ExpressionExperiment ee) { return this.expressionExperimentDao.getLastArrayDesignUpdate(ee); } @Override @Transactional(readOnly = true) public Map<Long, AuditEvent> getLastLinkAnalysis(final Collection<Long> ids) { return this.getLastEvent(this.load(ids), LinkAnalysisEvent.Factory.newInstance()); } @Override @Transactional(readOnly = true) public Map<Long, AuditEvent> getLastMissingValueAnalysis(final Collection<Long> ids) { return this.getLastEvent(this.load(ids), MissingValueAnalysisEvent.Factory.newInstance()); } @Override @Transactional(readOnly = true) public Map<Long, AuditEvent> getLastProcessedDataUpdate(final Collection<Long> ids) { return this.getLastEvent(this.load(ids), ProcessedVectorComputationEvent.Factory.newInstance()); } @Override @Transactional(readOnly = true) public Map<Taxon, Long> getPerTaxonCount() { return this.expressionExperimentDao.getPerTaxonCount(); } @Override @Transactional(readOnly = true) public Map<Long, Integer> getPopulatedFactorCounts(final Collection<Long> ids) { return this.expressionExperimentDao.getPopulatedFactorCounts(ids); } @Override @Transactional(readOnly = true) public Map<Long, Integer> getPopulatedFactorCountsExcludeBatch(final Collection<Long> ids) { return this.expressionExperimentDao.getPopulatedFactorCountsExcludeBatch(ids); } @Override @Transactional(readOnly = true) public Collection<QuantitationType> getPreferredQuantitationType(final ExpressionExperiment ee) { Collection<QuantitationType> preferredQuantitationTypes = new HashSet<>(); Collection<QuantitationType> quantitationTypes = this.getQuantitationTypes(ee); for (QuantitationType qt : quantitationTypes) { if (qt.getIsPreferred()) { preferredQuantitationTypes.add(qt); } } return preferredQuantitationTypes; } @Override @Transactional(readOnly = true) public Map<QuantitationType, Integer> getQuantitationTypeCountById(final Long id) { return this.expressionExperimentDao.getQuantitationTypeCountById(id); } @Override @Transactional(readOnly = true) public Collection<QuantitationType> getQuantitationTypes(final ExpressionExperiment expressionExperiment) { return this.expressionExperimentDao.getQuantitationTypes(expressionExperiment); } @Override @Transactional(readOnly = true) public Collection<QuantitationType> getQuantitationTypes(final ExpressionExperiment expressionExperiment, final ArrayDesign arrayDesign) { return this.expressionExperimentDao.getQuantitationTypes(expressionExperiment, arrayDesign); } @Override @Transactional(readOnly = true) public Map<ExpressionExperiment, Collection<AuditEvent>> getSampleRemovalEvents( final Collection<ExpressionExperiment> expressionExperiments) { return this.expressionExperimentDao.getSampleRemovalEvents(expressionExperiments); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperimentSubSet> getSubSets(final ExpressionExperiment expressionExperiment) { return this.expressionExperimentDao.getSubSets(expressionExperiment); } @Override @Transactional(readOnly = true) public <T extends BioAssaySet> Map<T, Taxon> getTaxa(Collection<T> bioAssaySets) { return this.expressionExperimentDao.getTaxa(bioAssaySets); } @Override @Transactional(readOnly = true) public Taxon getTaxon(final BioAssaySet bioAssaySet) { return this.expressionExperimentDao.getTaxon(bioAssaySet); } @Override public boolean isRNASeq(ExpressionExperiment expressionExperiment) { Collection<ArrayDesign> ads = this.expressionExperimentDao.getArrayDesignsUsed(expressionExperiment); // FIXME Because we switch platforms, the actual platform type for RNA-seq will be GENELIST once the data are processed. But we could look at the bioAssay.originalPlatform return ads.size() <= 1 && (ads.iterator().next().getTechnologyType().equals(TechnologyType.SEQUENCING) || ads.iterator().next().getTechnologyType().equals(TechnologyType.GENELIST)); } /** * @param ee the expression experiment to be checked for trouble. This method will usually be preferred over * checking * the curation details of the object directly, as this method also checks all the array designs the * given * experiment belongs to. * @return true, if the given experiment, or any of its parenting array designs is troubled. False otherwise */ @Override public boolean isTroubled(ExpressionExperiment ee) { if (ee.getCurationDetails().getTroubled()) return true; Collection<ArrayDesign> ads = this.getArrayDesignsUsed(ee); for (ArrayDesign ad : ads) { if (ad.getCurationDetails().getTroubled()) return true; } return false; } @Override @Transactional(readOnly = true) public Collection<ExpressionExperimentValueObject> loadAllValueObjectsOrdered(String orderField, boolean descending) { return this.expressionExperimentDao.loadAllValueObjectsOrdered(orderField, descending); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperimentValueObject> loadAllValueObjectsTaxon(Taxon taxon) { return this.expressionExperimentDao.loadAllValueObjectsTaxon(taxon); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperimentValueObject> loadAllValueObjectsTaxonOrdered(String orderField, boolean descending, Taxon taxon) { return this.expressionExperimentDao.loadAllValueObjectsTaxonOrdered(orderField, descending, taxon); } @Override public Collection<ExpressionExperimentDetailsValueObject> loadDetailsValueObjects(String orderField, boolean descending, Collection<Long> ids, Taxon taxon, int limit, int start) { return this.expressionExperimentDao.loadDetailsValueObjects(orderField, descending, ids, taxon, limit, start); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> loadLackingFactors() { return this.expressionExperimentDao.loadLackingFactors(); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperiment> loadLackingTags() { return this.expressionExperimentDao.loadLackingTags(); } @Override @Transactional(readOnly = true) public Collection<ExpressionExperimentValueObject> loadValueObjects(final Collection<Long> ids, boolean maintainOrder) { return this.expressionExperimentDao.loadValueObjects(ids, maintainOrder); } @Override @Transactional(readOnly = true) public List<ExpressionExperimentValueObject> loadValueObjectsOrdered(String orderField, boolean descending, Collection<Long> ids) { return new ArrayList<>(this.expressionExperimentDao.loadValueObjectsOrdered(orderField, descending, ids)); } @Override @Transactional public int removeRawVectors(ExpressionExperiment ee, QuantitationType qt) { ExpressionExperiment eeToUpdate = this.load(ee.getId()); Collection<RawExpressionDataVector> vectorsToRemove = new ArrayList<>(); for (RawExpressionDataVector oldV : eeToUpdate.getRawExpressionDataVectors()) { if (oldV.getQuantitationType().equals(qt)) { vectorsToRemove.add(oldV); } } if (vectorsToRemove.isEmpty()) { throw new IllegalArgumentException("No vectors to remove for quantitation type=" + qt); } eeToUpdate.getRawExpressionDataVectors().removeAll(vectorsToRemove); AbstractService.log.info("Removing unused quantitation type: " + qt); eeToUpdate.getQuantitationTypes().remove(qt); return vectorsToRemove.size(); } @Override @Transactional public ExpressionExperiment replaceRawVectors(ExpressionExperiment ee, Collection<RawExpressionDataVector> newVectors) { if (newVectors == null || newVectors.isEmpty()) { throw new UnsupportedOperationException("Only use this method for replacing vectors, not erasing them"); } // to attach to session correctly. ExpressionExperiment eeToUpdate = this.load(ee.getId()); Collection<QuantitationType> qtsToRemove = new HashSet<>(); for (RawExpressionDataVector oldV : eeToUpdate.getRawExpressionDataVectors()) { qtsToRemove.add(oldV.getQuantitationType()); } rawExpressionDataVectorDao.remove(eeToUpdate.getRawExpressionDataVectors()); // should not be necessary processedVectorService.remove(eeToUpdate.getProcessedExpressionDataVectors()); // should not be necessary eeToUpdate.getProcessedExpressionDataVectors().clear(); // this should be sufficient eeToUpdate.getRawExpressionDataVectors().clear(); // should be sufficient // These QTs might still be getting used by the replaced vectors. for (RawExpressionDataVector newVec : newVectors) { qtsToRemove.remove(newVec.getQuantitationType()); } for (QuantitationType oldQt : qtsToRemove) { quantitationTypeDao.remove(oldQt); } // Split the vectors up by bioassay dimension, if need be. This could be modified to handle multiple quantitation types if need be. Map<BioAssayDimension, Collection<RawExpressionDataVector>> BADs = new HashMap<>(); for (RawExpressionDataVector vec : newVectors) { BioAssayDimension b = vec.getBioAssayDimension(); if (!BADs.containsKey(b)) { BADs.put(b, new HashSet<RawExpressionDataVector>()); } BADs.get(b).add(vec); } for (Collection<RawExpressionDataVector> vectors : BADs.values()) { ee = this.addRawVectors(eeToUpdate, vectors); } return ee; } /** * Will add the characteristic to the expression experiment and persist the changes. * * @param vc If the evidence code is null, it will be filled in with IC. A category and value must be provided. * @param ee the experiment to add the characteristics to. */ @Override public void saveExpressionExperimentStatement(Characteristic vc, ExpressionExperiment ee) { ee = this.thawLite(this.load(ee.getId())); // Necessary to make sure we have the persistent version of the given ee. ontologyService.addExpressionExperimentStatement(vc, ee); this.update(ee); } /** * Will add all the vocab characteristics to the expression experiment and persist the changes. * * @param vc Collection of the characteristics to be added to the experiment. If the evidence code is null, it will * be filled in with IC. A category and value must be provided. * @param ee the experiment to add the characteristics to. */ @Override public void saveExpressionExperimentStatements(Collection<Characteristic> vc, ExpressionExperiment ee) { for (Characteristic characteristic : vc) { this.saveExpressionExperimentStatement(characteristic, ee); } } @Override @Transactional(readOnly = true) public ExpressionExperiment thaw(final ExpressionExperiment expressionExperiment) { return this.expressionExperimentDao.thaw(expressionExperiment); } @Override @Transactional(readOnly = true) public ExpressionExperiment thawBioAssays(final ExpressionExperiment expressionExperiment) { return this.expressionExperimentDao.thawBioAssays(expressionExperiment); } @Override @Transactional(readOnly = true) public ExpressionExperiment thawLite(final ExpressionExperiment expressionExperiment) { return this.expressionExperimentDao.thawWithoutVectors(expressionExperiment); } @Override public ExpressionExperiment thawLiter(final ExpressionExperiment expressionExperiment) { return this.expressionExperimentDao.thawForFrontEnd(expressionExperiment); } @Override @Transactional public ExpressionExperiment findOrCreate(final ExpressionExperiment expressionExperiment) { return this.expressionExperimentDao.findOrCreate(expressionExperiment); } @Override @Transactional public void remove(Long id) { final ExpressionExperiment ee = this.load(id); if (!securityService.isEditable(ee)) { throw new SecurityException( "Error performing 'ExpressionExperimentService.remove(ExpressionExperiment expressionExperiment)' --> " + " You do not have permission to edit this experiment."); } // Remove subsets Collection<ExpressionExperimentSubSet> subsets = this.getSubSets(ee); for (ExpressionExperimentSubSet subset : subsets) { expressionExperimentSubSetService.remove(subset); } // Remove differential expression analyses this.differentialExpressionAnalysisService.removeForExperiment(ee); // Remove any sample coexpression matrices this.sampleCoexpressionAnalysisService.removeForExperiment(ee); // Remove PCA this.principalComponentAnalysisService.removeForExperiment(ee); // Remove coexpression analyses this.coexpressionAnalysisService.removeForExperiment(ee); /* * Delete any expression experiment sets that only have this one ee in it. If possible remove this experiment * from other sets, and update them. IMPORTANT, this section assumes that we already checked for gene2gene * analyses! */ Collection<ExpressionExperimentSet> sets = this.expressionExperimentSetService.find(ee); for (ExpressionExperimentSet eeSet : sets) { if (eeSet.getExperiments().size() == 1 && eeSet.getExperiments().iterator().next().equals(ee)) { AbstractService.log.info("Removing from set " + eeSet); this.expressionExperimentSetService.remove(eeSet); // remove the set because in only contains this experiment } else { AbstractService.log.info("Removing " + ee + " from " + eeSet); eeSet.getExperiments().remove(ee); this.expressionExperimentSetService.update(eeSet); // update set to not reference this experiment. } } this.expressionExperimentDao.remove(ee); } /** * @see ExpressionExperimentService#remove(ExpressionExperiment) */ @Override @Transactional public void remove(ExpressionExperiment expressionExperiment) { // Can not call DAO directly since we have to do some service-layer level house keeping this.remove(expressionExperiment.getId()); } @Override @Transactional public void update(ExpressionExperiment entity) { super.update(entity); } /** * @see ExpressionExperimentDaoImpl#loadValueObjectsPreFilter(int, int, String, boolean, List) for * description (no but seriously do look it might not work as you would expect). */ @Override @Transactional(readOnly = true) public Collection<ExpressionExperimentValueObject> loadValueObjectsPreFilter(int offset, int limit, String orderBy, boolean asc, List<ObjectFilter[]> filter) { return this.expressionExperimentDao.loadValueObjectsPreFilter(offset, limit, orderBy, asc, filter); } private Collection<? extends AnnotationValueObject> getAnnotationsByFactorValues(Long eeId) { return this.expressionExperimentDao.getAnnotationsByFactorvalues(eeId); } private Collection<? extends AnnotationValueObject> getAnnotationsByBioMaterials(Long eeId) { return this.expressionExperimentDao.getAnnotationsByBioMaterials(eeId); } private boolean getHasBeenBatchCorrected(ExpressionExperiment ee) { for (QuantitationType qt : this.expressionExperimentDao.getQuantitationTypes(ee)) { if (qt.getIsBatchCorrected()) { return true; } } return false; } /** * @param ees experiments * @param type event type * @return a map of the expression experiment ids to the last audit event for the given audit event type the * map * can contain nulls if the specified auditEventType isn't found for a given expression experiment id */ private Map<Long, AuditEvent> getLastEvent(Collection<ExpressionExperiment> ees, AuditEventType type) { Map<Long, AuditEvent> lastEventMap = new HashMap<>(); AuditEvent last; for (ExpressionExperiment experiment : ees) { last = this.auditEventDao.getLastEvent(experiment, type.getClass()); lastEventMap.put(experiment.getId(), last); } return lastEventMap; } /* * (non-Javadoc) * * @see * ubic.gemma.persistence.service.expression.experiment.ExpressionExperimentService#isBlackListed(java.lang.String) */ @Override public boolean isBlackListed(String geoAccession) { return this.blacklistedEntityDao.isBlacklisted(geoAccession); } }