From 026e3c8cd7a67e18413865dd878c2b527f1ca9e3 Mon Sep 17 00:00:00 2001 From: Guillaume Poirier-Morency Date: Thu, 27 Apr 2023 03:19:07 -0700 Subject: [PATCH] WIP Metadata can be attached at both ExpressionExperiment and BioAssay levels. --- .../gemma/core/apps/RNASeqDataAddCli.java | 9 ++++ .../core/loader/expression/DataUpdater.java | 5 +++ .../loader/expression/DataUpdaterImpl.java | 32 ++++++++++---- .../model/expression/AdditionalMetadata.java | 26 +++++++++++ .../model/expression/bioAssay/BioAssay.java | 13 ++++++ .../experiment/ExpressionExperiment.java | 15 ++++++- .../expression/experiment/MetadataType.java | 24 +++++++++++ .../experiment/ExpressionExperimentDao.java | 16 +++++++ .../ExpressionExperimentDaoImpl.java | 32 +++++++++++++- .../ExpressionExperimentService.java | 8 ++++ .../ExpressionExperimentServiceImpl.java | 22 ++++++++++ .../src/main/resources/hibernate.cfg.xml | 1 + .../model/analysis/Investigation.hbm.xml | 7 +++ .../expression/AdditionalMetadata.hbm.xml | 32 ++++++++++++++ .../expression/bioAssay/BioAssay.hbm.xml | 6 +++ .../preprocess/MeanVarianceServiceTest.java | 1 - .../ExpressionExperimentDaoTest.java | 43 ++++++++++++++++++- 17 files changed, 278 insertions(+), 14 deletions(-) create mode 100644 gemma-core/src/main/java/ubic/gemma/model/expression/AdditionalMetadata.java create mode 100644 gemma-core/src/main/java/ubic/gemma/model/expression/experiment/MetadataType.java create mode 100644 gemma-core/src/main/resources/ubic/gemma/model/expression/AdditionalMetadata.hbm.xml diff --git a/gemma-cli/src/main/java/ubic/gemma/core/apps/RNASeqDataAddCli.java b/gemma-cli/src/main/java/ubic/gemma/core/apps/RNASeqDataAddCli.java index 669d4c28c9..ca4777fe0e 100644 --- a/gemma-cli/src/main/java/ubic/gemma/core/apps/RNASeqDataAddCli.java +++ b/gemma-cli/src/main/java/ubic/gemma/core/apps/RNASeqDataAddCli.java @@ -29,8 +29,10 @@ import ubic.gemma.model.expression.experiment.ExpressionExperiment; import ubic.gemma.persistence.service.expression.arrayDesign.ArrayDesignService; +import java.io.File; import java.io.IOException; import java.util.Collection; +import java.util.Collections; /** * Designed to add count and/or RPKM data to a data set that has only meta-data. @@ -50,6 +52,7 @@ public class RNASeqDataAddCli extends ExpressionExperimentManipulatingCLI { private Integer readLength = null; private String rpkmFile = null; private boolean justbackfillLog2cpm = false; + private File[] additionalMetadata; @Override public CommandGroup getCommandGroup() { @@ -70,6 +73,10 @@ protected void buildOptions( Options options ) { options.addOption( "log2cpm", "Just compute log2cpm from the existing stored count data (backfill); batchmode OK, no other options needed" ); + options.addOption( Option.builder( "am" ) + .longOpt( "additional-metadata" ) + .type( File.class ) + .build() ); } @Override @@ -192,6 +199,8 @@ protected void doWork() throws Exception { serv.addCountData( ee, targetArrayDesign, countMatrix, rpkmMatrix, readLength, isPairedReads, allowMissingSamples ); + serv.addAdditionalMetadata( ee, additionalMetadata, Collections.emptyMap() ); + } catch ( IOException e ) { throw new Exception( "Failed while processing " + ee, e ); } diff --git a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/DataUpdater.java b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/DataUpdater.java index 8a760d58f4..20027ca353 100644 --- a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/DataUpdater.java +++ b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/DataUpdater.java @@ -4,9 +4,12 @@ import ubic.gemma.core.datastructure.matrix.ExpressionDataDoubleMatrix; import ubic.gemma.model.common.quantitationtype.QuantitationType; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; +import ubic.gemma.model.expression.bioAssay.BioAssay; import ubic.gemma.model.expression.experiment.ExpressionExperiment; +import java.io.File; import java.io.IOException; +import java.util.Map; public interface DataUpdater { void addAffyDataFromAPTOutput( ExpressionExperiment ee, String pathToAptOutputFile ) throws IOException; @@ -26,4 +29,6 @@ void replaceData( ExpressionExperiment ee, ArrayDesign targetPlatform, Quantitat ExpressionExperiment replaceData( ExpressionExperiment ee, ArrayDesign targetPlatform, ExpressionDataDoubleMatrix data ); + + void addAdditionalMetadata( ExpressionExperiment ee, File[] additionalMetadata, Map additionalMetadataPerBioAssay ); } diff --git a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/DataUpdaterImpl.java b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/DataUpdaterImpl.java index 36692411e4..5ab700ca69 100644 --- a/gemma-core/src/main/java/ubic/gemma/core/loader/expression/DataUpdaterImpl.java +++ b/gemma-core/src/main/java/ubic/gemma/core/loader/expression/DataUpdaterImpl.java @@ -21,6 +21,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -49,6 +50,7 @@ import ubic.gemma.model.expression.biomaterial.BioMaterial; import ubic.gemma.model.expression.designElement.CompositeSequence; import ubic.gemma.model.expression.experiment.ExpressionExperiment; +import ubic.gemma.model.expression.experiment.MetadataType; 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.AuditTrailService; @@ -61,6 +63,7 @@ import ubic.gemma.persistence.service.expression.experiment.ExpressionExperimentService; import ubic.gemma.persistence.util.EntityUtils; +import java.io.File; import java.io.IOException; import java.util.*; @@ -189,9 +192,10 @@ public void addAffyDataFromAPTOutput( ExpressionExperiment ee, String pathToAptO * switched to use it. * @param countMatrix Representing 'raw' counts (added after rpkm, if provided). * @param rpkmMatrix Representing per-gene normalized data, optional (RPKM or FPKM) - * @param allowMissingSamples if true, samples that are missing data will be deleted from the experiment. - * @param isPairedReads is paired reads * @param readLength read length + * @param isPairedReads is paired reads + * @param allowMissingSamples if true, samples that are missing data will be deleted from the experiment. + * @param additionalMetadata */ @Override @Transactional(propagation = Propagation.NEVER) @@ -280,7 +284,6 @@ public void addCountData( ExpressionExperiment ee, ArrayDesign targetArrayDesign this.addData( ee, targetArrayDesign, rpkmEEMatrix ); } - } /** @@ -545,11 +548,11 @@ public void reprocessAffyDataFromCel( ExpressionExperiment ee ) { * selected experiment. Will do postprocessing if the data quantitationType is 'preferred', but if there is already * a preferred quantitation type, an error will be thrown. * - * @param ee ee - * @param targetPlatform optional; if null, uses the platform already used (if there is just one; you can't use - * this - * for a multi-platform dataset) - * @param data to slot in + * @param ee ee + * @param targetPlatform optional; if null, uses the platform already used (if there is just one; you can't use + * this + * for a multi-platform dataset) + * @param data to slot in * @return ee */ @Override @@ -673,6 +676,19 @@ public ExpressionExperiment replaceData( ExpressionExperiment ee, ArrayDesign ta return ee; } + @Override + @Transactional(propagation = Propagation.NEVER) + public void addAdditionalMetadata( ExpressionExperiment ee, File[] additionalMetadata, Map additionalMetadataPerBioAssay ) { + for ( File am : additionalMetadata ) { + experimentService.addAdditionalMetadata( ee, MetadataType.PREPROCESSING, am, MediaType.TEXT_PLAIN_VALUE ); + } + for ( Map.Entry e : additionalMetadataPerBioAssay.entrySet() ) { + for ( File am : e.getValue() ) { + experimentService.addAdditionalMetadata( ee, e.getKey(), MetadataType.PREPROCESSING, am, MediaType.TEXT_PLAIN_VALUE ); + } + } + } + /** * RNA-seq * diff --git a/gemma-core/src/main/java/ubic/gemma/model/expression/AdditionalMetadata.java b/gemma-core/src/main/java/ubic/gemma/model/expression/AdditionalMetadata.java new file mode 100644 index 0000000000..63c17d60a9 --- /dev/null +++ b/gemma-core/src/main/java/ubic/gemma/model/expression/AdditionalMetadata.java @@ -0,0 +1,26 @@ +package ubic.gemma.model.expression; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import ubic.gemma.model.common.Describable; +import ubic.gemma.model.expression.bioAssay.BioAssay; +import ubic.gemma.model.expression.experiment.ExpressionExperiment; +import ubic.gemma.model.expression.experiment.MetadataType; + +import java.sql.Blob; + +/** + * Metadata associated to an {@link ExpressionExperiment} or {@link BioAssay}. + * @author poirigui + */ +@Data +@EqualsAndHashCode(of = { "id" }) +public class AdditionalMetadata implements Describable { + + private Long id; + private String name; + private String description; + private MetadataType type; + private Blob contents; + private String mediaType; +} diff --git a/gemma-core/src/main/java/ubic/gemma/model/expression/bioAssay/BioAssay.java b/gemma-core/src/main/java/ubic/gemma/model/expression/bioAssay/BioAssay.java index cbe30e3ea7..6bc20de732 100644 --- a/gemma-core/src/main/java/ubic/gemma/model/expression/bioAssay/BioAssay.java +++ b/gemma-core/src/main/java/ubic/gemma/model/expression/bioAssay/BioAssay.java @@ -23,10 +23,13 @@ import ubic.gemma.model.common.description.DatabaseEntry; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; import ubic.gemma.model.expression.biomaterial.BioMaterial; +import ubic.gemma.model.expression.AdditionalMetadata; import javax.persistence.Transient; import java.io.Serializable; import java.util.Date; +import java.util.HashSet; +import java.util.Set; /** * Represents the bringing together of a biomaterial with an assay of some sort (typically an expression assay). We @@ -60,6 +63,8 @@ public class BioAssay extends AbstractDescribable implements gemma.gsec.model.Se */ private String fastqHeaders; + private Set additionalMetadata = new HashSet<>(); + @Override public int hashCode() { int hashCode; @@ -215,6 +220,14 @@ public void setFastqHeaders( String fastqHeaders ) { this.fastqHeaders = fastqHeaders; } + public Set getAdditionalMetadata() { + return additionalMetadata; + } + + public void setAdditionalMetadata( Set additionalMetadata ) { + this.additionalMetadata = additionalMetadata; + } + public static final class Factory { public static BioAssay newInstance() { diff --git a/gemma-core/src/main/java/ubic/gemma/model/expression/experiment/ExpressionExperiment.java b/gemma-core/src/main/java/ubic/gemma/model/expression/experiment/ExpressionExperiment.java index a1722158bc..72e0d357c2 100644 --- a/gemma-core/src/main/java/ubic/gemma/model/expression/experiment/ExpressionExperiment.java +++ b/gemma-core/src/main/java/ubic/gemma/model/expression/experiment/ExpressionExperiment.java @@ -14,7 +14,6 @@ */ package ubic.gemma.model.expression.experiment; -import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -26,6 +25,7 @@ import ubic.gemma.model.common.auditAndSecurity.curation.CurationDetails; import ubic.gemma.model.common.description.Characteristic; import ubic.gemma.model.common.quantitationtype.QuantitationType; +import ubic.gemma.model.expression.AdditionalMetadata; import ubic.gemma.model.expression.bioAssay.BioAssay; import ubic.gemma.model.expression.bioAssayData.MeanVarianceRelation; import ubic.gemma.model.expression.bioAssayData.ProcessedExpressionDataVector; @@ -81,6 +81,11 @@ public void setNumberOfSamples( Integer numberofSamples ) { private Set allCharacteristics; + /** + * A collection of additional metadata blobs. + */ + private Set additionalMetadata = new HashSet<>(); + @Override public ExpressionExperimentValueObject createValueObject() { return new ExpressionExperimentValueObject( this ); @@ -280,6 +285,14 @@ public void setTaxon( Taxon taxon ) { this.taxon = taxon; } + public Set getAdditionalMetadata() { + return additionalMetadata; + } + + public void setAdditionalMetadata( Set additionalMetadata ) { + this.additionalMetadata = additionalMetadata; + } + @Override public String toString() { return super.toString() + ( shortName != null ? " Short Name=" + shortName : "" ); diff --git a/gemma-core/src/main/java/ubic/gemma/model/expression/experiment/MetadataType.java b/gemma-core/src/main/java/ubic/gemma/model/expression/experiment/MetadataType.java new file mode 100644 index 0000000000..1ba5656b3f --- /dev/null +++ b/gemma-core/src/main/java/ubic/gemma/model/expression/experiment/MetadataType.java @@ -0,0 +1,24 @@ +package ubic.gemma.model.expression.experiment; + +import ubic.gemma.model.expression.bioAssay.BioAssay; + +public enum MetadataType { + /** + * A sequencing QC report. + *

+ * Example: a FastQC report attached to a specific {@link BioAssay}. + */ + SEQUENCING_QC_REPORT, + /** + * A sequencing alignment report. + *

+ * Example: STAR's Log.final.out file on a {@link BioAssay} + */ + SEQUENCING_ALIGNMENT_REPORT, + /** + * An overall sequencing report. + *

+ * Example: a MultiQC report on a {@link ExpressionExperiment} + */ + SEQUENCING_OVERALL_REPORT, +} diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDao.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDao.java index 1943672c61..e439b06658 100644 --- a/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDao.java +++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDao.java @@ -7,6 +7,7 @@ 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.expression.AdditionalMetadata; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; import ubic.gemma.model.expression.bioAssay.BioAssay; import ubic.gemma.model.expression.bioAssayData.BioAssayDimension; @@ -18,11 +19,13 @@ import ubic.gemma.persistence.service.BrowsingDao; import ubic.gemma.persistence.service.FilteringVoEnabledDao; import ubic.gemma.persistence.service.common.auditAndSecurity.curation.CuratableDao; +import ubic.gemma.persistence.service.expression.bioAssay.BioAssayDao; import ubic.gemma.persistence.util.Filters; import ubic.gemma.persistence.util.Slice; import ubic.gemma.persistence.util.Sort; import javax.annotation.Nullable; +import java.io.InputStream; import java.util.Collection; import java.util.Date; import java.util.List; @@ -232,4 +235,17 @@ Map> getSampleRemovalEvents( long countTroubledPlatforms( ExpressionExperiment ee ); MeanVarianceRelation updateMeanVarianceRelation( ExpressionExperiment ee, MeanVarianceRelation mvr ); + + /** + * Add metadata on a given dataset. + */ + AdditionalMetadata addAdditionalMetadata( ExpressionExperiment ee, MetadataType type, InputStream additionalMetadata, long length, String mediaType ); + + /** + * Add metadata on a specific bioassay. + *

+ * FIXME: this should probably be relocated in {@link BioAssayDao}. + * @throws IllegalArgumentException if the bioassay does not belong to the expression experiment + */ + AdditionalMetadata addAdditionalMetadata( ExpressionExperiment ee, BioAssay sample, MetadataType metadataType, InputStream stream, long length, String mediaType ) throws IllegalArgumentException; } diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDaoImpl.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDaoImpl.java index 72179eab90..03a668f7e6 100644 --- a/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDaoImpl.java +++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDaoImpl.java @@ -41,6 +41,7 @@ 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.expression.AdditionalMetadata; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; import ubic.gemma.model.expression.arrayDesign.ArrayDesignValueObject; import ubic.gemma.model.expression.bioAssay.BioAssay; @@ -60,8 +61,8 @@ import ubic.gemma.persistence.util.*; import javax.annotation.Nullable; +import java.io.InputStream; import java.util.*; -import java.util.regex.Pattern; import java.util.stream.Collectors; import static java.util.stream.Collectors.groupingBy; @@ -430,7 +431,7 @@ public Collection findByTaxon( Taxon taxon ) { //language=HQL // final String queryString = // "select distinct ee from ExpressionExperiment as ee " + "inner join ee.bioAssays as ba " - // + "inner join ba.sampleUsed as sample where sample.sourceTaxon = :taxon "; + // + "inner join ba.sampleUsed as bioAssay where bioAssay.sourceTaxon = :taxon "; final String queryString = "select ee from ExpressionExperiment as ee where ee.taxon = (:taxon)"; //noinspection unchecked @@ -701,6 +702,32 @@ public MeanVarianceRelation updateMeanVarianceRelation( ExpressionExperiment ee, return mvr; } + @Override + public AdditionalMetadata addAdditionalMetadata( ExpressionExperiment ee, MetadataType type, InputStream stream, long length, String mediaType ) { + AdditionalMetadata am = createAdditionalMetadata( type, stream, length ); + ee.getAdditionalMetadata().add( am ); + return am; + } + + @Override + public AdditionalMetadata addAdditionalMetadata( ExpressionExperiment ee, BioAssay bioAssay, MetadataType type, InputStream stream, long length, String mediaType ) throws IllegalArgumentException { + if ( ee.getBioAssays().contains( bioAssay ) ) { + throw new IllegalArgumentException( String.format( "%s is not part of %s", bioAssay, ee ) ); + } + AdditionalMetadata am = createAdditionalMetadata( type, stream, length ); + bioAssay.getAdditionalMetadata().add( am ); + return am; + } + + private AdditionalMetadata createAdditionalMetadata( MetadataType type, InputStream stream, long length ) { + AdditionalMetadata meta = new AdditionalMetadata(); + meta.setType( type ); + meta.setContents( getSessionFactory().getCurrentSession().getLobHelper().createBlob( stream, length ) ); + meta.setMediaType( "text/plain" ); + getSessionFactory().getCurrentSession().persist( meta ); + return meta; + } + @Override public Collection getArrayDesignsUsed( BioAssaySet bas ) { @@ -1701,6 +1728,7 @@ protected void configureFilterableProperties( FilterablePropertiesConfigurer con configurer.unregisterProperty( "source" ); configurer.unregisterProperty( "otherParts.size" ); configurer.unregisterProperty( "otherRelevantPublications.size" ); + configurer.unregisterProperty( "additionalMetadata.size" ); configurer.unregisterProperties( p -> p.endsWith( "externalDatabases.size" ) ); diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentService.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentService.java index ffead941f1..d250a5b671 100644 --- a/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentService.java +++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentService.java @@ -31,6 +31,7 @@ import ubic.gemma.model.common.description.DatabaseEntry; import ubic.gemma.model.common.quantitationtype.QuantitationType; import ubic.gemma.model.common.quantitationtype.QuantitationTypeValueObject; +import ubic.gemma.model.expression.AdditionalMetadata; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; import ubic.gemma.model.expression.bioAssay.BioAssay; import ubic.gemma.model.expression.bioAssayData.BioAssayDimension; @@ -48,6 +49,7 @@ import javax.annotation.CheckReturnValue; import javax.annotation.Nullable; +import java.io.File; import java.util.*; /** @@ -627,4 +629,10 @@ Map> getSampleRemovalEvents( @Secured({ "GROUP_USER" }) MeanVarianceRelation updateMeanVarianceRelation( ExpressionExperiment ee, MeanVarianceRelation mvr ); + + @Secured({ "GROUP_USER" }) + AdditionalMetadata addAdditionalMetadata( ExpressionExperiment ee, MetadataType type, File additionalMetadata, String mediaType ); + + @Secured({ "GROUP_USER" }) + AdditionalMetadata addAdditionalMetadata( ExpressionExperiment ee, BioAssay sample, MetadataType metadataType, File additionalMetadata, String textPlainValue ); } diff --git a/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentServiceImpl.java b/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentServiceImpl.java index b91cf80cb8..eee904ce0f 100755 --- a/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentServiceImpl.java +++ b/gemma-core/src/main/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentServiceImpl.java @@ -53,6 +53,7 @@ import ubic.gemma.model.common.quantitationtype.QuantitationType; import ubic.gemma.model.common.quantitationtype.QuantitationTypeValueObject; import ubic.gemma.model.common.search.SearchSettings; +import ubic.gemma.model.expression.AdditionalMetadata; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; import ubic.gemma.model.expression.arrayDesign.TechnologyType; import ubic.gemma.model.expression.bioAssay.BioAssay; @@ -78,6 +79,7 @@ import ubic.gemma.persistence.util.Sort; import javax.annotation.Nullable; +import java.io.*; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -593,6 +595,26 @@ public Filters getFiltersWithInferredAnnotations( Filters f ) { return f2; } + @Override + @Transactional + public AdditionalMetadata addAdditionalMetadata( ExpressionExperiment ee, MetadataType type, File additionalMetadata, String mediaType ) { + try ( InputStream stream = new FileInputStream( additionalMetadata ) ) { + return expressionExperimentDao.addAdditionalMetadata( ee, type, stream, additionalMetadata.length(), mediaType ); + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + } + + @Override + @Transactional + public AdditionalMetadata addAdditionalMetadata( ExpressionExperiment ee, BioAssay sample, MetadataType metadataType, File additionalMetadata, String mediaType ) { + try ( InputStream stream = new FileInputStream( additionalMetadata ) ) { + return expressionExperimentDao.addAdditionalMetadata( ee, sample, metadataType, stream, additionalMetadata.length(), mediaType ); + } catch ( IOException e ) { + throw new RuntimeException( e ); + } + } + @Override @Transactional(readOnly = true) public ExpressionExperiment loadWithCharacteristics( Long id ) { diff --git a/gemma-core/src/main/resources/hibernate.cfg.xml b/gemma-core/src/main/resources/hibernate.cfg.xml index 2ed4bacf4d..1af579be60 100644 --- a/gemma-core/src/main/resources/hibernate.cfg.xml +++ b/gemma-core/src/main/resources/hibernate.cfg.xml @@ -58,6 +58,7 @@ + diff --git a/gemma-core/src/main/resources/ubic/gemma/model/analysis/Investigation.hbm.xml b/gemma-core/src/main/resources/ubic/gemma/model/analysis/Investigation.hbm.xml index 130be64343..91ea533176 100644 --- a/gemma-core/src/main/resources/ubic/gemma/model/analysis/Investigation.hbm.xml +++ b/gemma-core/src/main/resources/ubic/gemma/model/analysis/Investigation.hbm.xml @@ -155,6 +155,13 @@ + + + + + + diff --git a/gemma-core/src/main/resources/ubic/gemma/model/expression/AdditionalMetadata.hbm.xml b/gemma-core/src/main/resources/ubic/gemma/model/expression/AdditionalMetadata.hbm.xml new file mode 100644 index 0000000000..a02a59d38f --- /dev/null +++ b/gemma-core/src/main/resources/ubic/gemma/model/expression/AdditionalMetadata.hbm.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + ubic.gemma.model.expression.experiment.MetadataType + true + + + + + + + + + + \ No newline at end of file diff --git a/gemma-core/src/main/resources/ubic/gemma/model/expression/bioAssay/BioAssay.hbm.xml b/gemma-core/src/main/resources/ubic/gemma/model/expression/bioAssay/BioAssay.hbm.xml index bde29bb426..5dbf2783ec 100644 --- a/gemma-core/src/main/resources/ubic/gemma/model/expression/bioAssay/BioAssay.hbm.xml +++ b/gemma-core/src/main/resources/ubic/gemma/model/expression/bioAssay/BioAssay.hbm.xml @@ -52,5 +52,11 @@ + + + + + diff --git a/gemma-core/src/test/java/ubic/gemma/core/analysis/preprocess/MeanVarianceServiceTest.java b/gemma-core/src/test/java/ubic/gemma/core/analysis/preprocess/MeanVarianceServiceTest.java index e6f615e933..8d3abc9497 100644 --- a/gemma-core/src/test/java/ubic/gemma/core/analysis/preprocess/MeanVarianceServiceTest.java +++ b/gemma-core/src/test/java/ubic/gemma/core/analysis/preprocess/MeanVarianceServiceTest.java @@ -33,7 +33,6 @@ import ubic.gemma.core.security.authorization.acl.AclTestUtils; import ubic.gemma.core.util.test.category.GeoTest; import ubic.gemma.core.util.test.category.SlowTest; -import ubic.gemma.model.common.auditAndSecurity.AuditAction; import ubic.gemma.model.common.quantitationtype.*; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; import ubic.gemma.model.expression.arrayDesign.TechnologyType; diff --git a/gemma-core/src/test/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDaoTest.java b/gemma-core/src/test/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDaoTest.java index a772da80ff..55e7246f33 100644 --- a/gemma-core/src/test/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDaoTest.java +++ b/gemma-core/src/test/java/ubic/gemma/persistence/service/expression/experiment/ExpressionExperimentDaoTest.java @@ -14,13 +14,19 @@ import ubic.gemma.model.expression.bioAssayData.RawExpressionDataVector; import ubic.gemma.model.expression.experiment.ExperimentalDesign; import ubic.gemma.model.expression.experiment.ExpressionExperiment; +import ubic.gemma.model.expression.AdditionalMetadata; +import ubic.gemma.model.expression.experiment.MetadataType; import ubic.gemma.persistence.service.common.auditAndSecurity.CurationDetailsDao; import ubic.gemma.persistence.util.TestComponent; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.sql.SQLException; import java.util.Collections; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.*; import static org.mockito.Mockito.mock; @ContextConfiguration @@ -94,6 +100,39 @@ public void testThawWithoutVectors() { assertTrue( Hibernate.isInitialized( ee.getExperimentalDesign() ) ); } + @Test + public void testAdditionalMetadata() throws SQLException, IOException { + ExpressionExperiment ee = createExpressionExperiment(); + AdditionalMetadata meta; + try ( InputStream stream = new ByteArrayInputStream( "Hello world!".getBytes() ) ) { + meta = expressionExperimentDao.addAdditionalMetadata( ee, MetadataType.PREPROCESSING, stream, 12L, "text/plain" ); + } + assertNotNull( meta.getId() ); + ee = reload( ee ); + assertThat( ee.getAdditionalMetadata() ) + .hasSize( 1 ); + assertThat( ee.getAdditionalMetadata().iterator().next().getContents().getBinaryStream() ) + .hasContent( "Hello world!" ); + } + + @Test + public void testAdditionalMetadataOnBioAssay() throws SQLException, IOException { + ExpressionExperiment ee = createExpressionExperiment(); + BioAssay ba = new BioAssay(); + sessionFactory.getCurrentSession().persist( ba ); + ee.getBioAssays().add( ba ); + AdditionalMetadata meta; + try ( InputStream stream = new ByteArrayInputStream( "Hello world!".getBytes() ) ) { + meta = expressionExperimentDao.addAdditionalMetadata( ee, ba, MetadataType.PREPROCESSING, stream, 12L, "text/plain" ); + } + assertNotNull( meta.getId() ); + ee = reload( ee ); + assertThat( ee.getAdditionalMetadata() ) + .hasSize( 1 ); + assertThat( ee.getAdditionalMetadata().iterator().next().getContents().getBinaryStream() ) + .hasContent( "Hello world!" ); + } + private ExpressionExperiment reload( ExpressionExperiment e ) { sessionFactory.getCurrentSession().flush(); sessionFactory.getCurrentSession().evict( e );