From 6fe914433583d904e2ea94ece76525f2f403cfdd Mon Sep 17 00:00:00 2001 From: felmer <felmer> Date: Wed, 31 Mar 2010 14:41:56 +0000 Subject: [PATCH] SE-229 dead code removed, unit tests adapted, and read-only grants on database added SVN: 15323 --- .../server/business/AbundanceManager.java | 57 ++- .../business/BusinessObjectFactory.java | 4 +- .../server/business/DAOFactoryWithCache.java | 376 ------------------ .../server/business/ErrorModel.java | 4 +- .../server/business/ProteinInfoTable.java | 96 ++--- .../server/dataaccess/IProteinQueryDAO.java | 17 - .../migration/MigrationStepFrom002To003.java | 71 ---- .../shared/dto/ProteinWithAbundances.java | 20 +- .../java/phosphonetx-applicationContext.xml | 3 +- .../source/java/service.properties | 2 - .../source/sql/postgresql/003/grant-003.sql | 18 + .../source/sql/postgresql/003/schema-003.png | Bin 0 -> 65092 bytes .../source/sql/postgresql/003/schema-003.sql | 16 +- .../migration/migration-002-003.sql | 7 - .../source/sql/postgresql/schema.dez | 51 ++- .../server/business/AbundanceManagerTest.java | 43 +- .../server/business/ProteinInfoTableTest.java | 109 +++-- 17 files changed, 217 insertions(+), 677 deletions(-) delete mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/DAOFactoryWithCache.java create mode 100644 rtd_phosphonetx/source/sql/postgresql/003/grant-003.sql create mode 100755 rtd_phosphonetx/source/sql/postgresql/003/schema-003.png diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManager.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManager.java index 38aff587293..b78bf393bf7 100644 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManager.java +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManager.java @@ -16,14 +16,15 @@ package ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.Set; import java.util.TreeSet; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability; +import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinAbundance; +import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProtein; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinWithAbundances; /** @@ -31,8 +32,7 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinWithAbundan */ class AbundanceManager { - private final Map<String, ProteinWithAbundances> proteins = - new LinkedHashMap<String, ProteinWithAbundances>(); + private final List<ProteinWithAbundances> proteins = new ArrayList<ProteinWithAbundances>(); private final ISampleProvider sampleProvider; @@ -41,21 +41,29 @@ class AbundanceManager AbundanceManager(ISampleProvider sampleProvider) { this.sampleProvider = sampleProvider; - } - - public void handle(ProteinReferenceWithProbability proteinReference) + + public void handle(ProteinReferenceWithProtein proteinReference, List<ProteinAbundance> listOrNull) { - ProteinWithAbundances protein = getOrCreateProtein(proteinReference); - String samplePermID = proteinReference.getSamplePermID(); - if (samplePermID != null) + String accessionNumber = proteinReference.getAccessionNumber(); + ProteinWithAbundances protein = new ProteinWithAbundances(); + protein.setCoverage(proteinReference.getCoverage()); + protein.setId(proteinReference.getId()); + protein.setDescription(proteinReference.getDescription()); + protein.setAccessionNumber(accessionNumber); + proteins.add(protein); + if (listOrNull != null) { - Long sampleID = getSampleIDOrParentSampleID(samplePermID); - sampleIDs.add(sampleID); - protein.addAbundanceFor(sampleID, proteinReference.getAbundance()); + for (ProteinAbundance proteinAbundance : listOrNull) + { + String samplePermID = proteinAbundance.getSamplePermID(); + Long sampleID = getSampleIDOrParentSampleID(samplePermID); + sampleIDs.add(sampleID); + protein.addAbundanceFor(sampleID, proteinAbundance.getAbundance()); + } } } - + private Long getSampleIDOrParentSampleID(String samplePermID) { Sample sample = sampleProvider.getSample(samplePermID); @@ -63,25 +71,9 @@ class AbundanceManager return parent == null ? sample.getId() : parent.getId(); } - private ProteinWithAbundances getOrCreateProtein(ProteinReferenceWithProbability proteinReference) - { - String accessionNumber = proteinReference.getAccessionNumber(); - ProteinWithAbundances protein = proteins.get(accessionNumber); - if (protein == null) - { - protein = new ProteinWithAbundances(); - protein.setCoverage(proteinReference.getCoverage()); - protein.setId(proteinReference.getId()); - protein.setDescription(proteinReference.getDescription()); - protein.setAccessionNumber(accessionNumber); - proteins.put(accessionNumber, protein); - } - return protein; - } - public Collection<ProteinWithAbundances> getProteinsWithAbundances() { - return proteins.values(); + return proteins; } public final Collection<Long> getSampleIDs() @@ -89,4 +81,5 @@ class AbundanceManager return sampleIDs; } + } diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/BusinessObjectFactory.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/BusinessObjectFactory.java index 209e514577f..966240e03b1 100644 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/BusinessObjectFactory.java +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/BusinessObjectFactory.java @@ -32,10 +32,10 @@ public class BusinessObjectFactory extends AbstractPluginBusinessObjectFactory private final IDAOFactory daoFactory; private final IPhosphoNetXDAOFactory specificDAOFactory; - public BusinessObjectFactory(IDAOFactory daoFactory, IPhosphoNetXDAOFactory specificDAOFactory, String typeOfCaching) + public BusinessObjectFactory(IDAOFactory daoFactory, IPhosphoNetXDAOFactory specificDAOFactory) { this.daoFactory = daoFactory; - this.specificDAOFactory = new DAOFactoryWithCache(specificDAOFactory, typeOfCaching); + this.specificDAOFactory = specificDAOFactory; } public ISampleLister createSampleLister(Session session) diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/DAOFactoryWithCache.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/DAOFactoryWithCache.java deleted file mode 100644 index 818ed880788..00000000000 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/DAOFactoryWithCache.java +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright 2010 ETH Zuerich, CISD - * - * 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 ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business; - -import it.unimi.dsi.fastutil.longs.LongSet; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; - -import net.lemnik.eodsql.DataSet; - -import org.apache.commons.lang.SerializationUtils; -import org.apache.log4j.Logger; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.core.simple.ParameterizedRowMapper; -import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; -import org.springframework.jdbc.support.lob.LobHandler; - -import ch.systemsx.cisd.common.logging.LogCategory; -import ch.systemsx.cisd.common.logging.LogFactory; -import ch.systemsx.cisd.dbmigration.DatabaseConfigurationContext; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.dataaccess.IPhosphoNetXDAOFactory; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.dataaccess.IProteinQueryDAO; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.IdentifiedPeptide; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.IdentifiedProtein; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProbabilityFDRMapping; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinAbundance; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReference; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbabilityAndPeptide; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProtein; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.SampleAbundance; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.Sequence; - -/** - * - * - * @author Franz-Josef Elmer - */ -class DAOFactoryWithCache implements IPhosphoNetXDAOFactory -{ - private static final class ProteinQueryDAO implements IProteinQueryDAO - { - private static final Logger operationLog = - LogFactory.getLogger(LogCategory.OPERATION, ProteinQueryDAO.class); - - private static final class DataSetProxy<T> implements DataSet<T> - { - private List<T> list; - DataSetProxy(List<T> list) - { - this.list = list; - } - public void add(int index, T element) - { - list.add(index, element); - } - public boolean add(T o) - { - return list.add(o); - } - public boolean addAll(Collection<? extends T> c) - { - return list.addAll(c); - } - public boolean addAll(int index, Collection<? extends T> c) - { - return list.addAll(index, c); - } - public void clear() - { - list.clear(); - } - public boolean contains(Object o) - { - return list.contains(o); - } - public boolean containsAll(Collection<?> c) - { - return list.containsAll(c); - } - @Override - public boolean equals(Object o) - { - return list.equals(o); - } - public T get(int index) - { - return list.get(index); - } - @Override - public int hashCode() - { - return list.hashCode(); - } - public int indexOf(Object o) - { - return list.indexOf(o); - } - public boolean isEmpty() - { - return list.isEmpty(); - } - public Iterator<T> iterator() - { - return list.iterator(); - } - public int lastIndexOf(Object o) - { - return list.lastIndexOf(o); - } - public ListIterator<T> listIterator() - { - return list.listIterator(); - } - public ListIterator<T> listIterator(int index) - { - return list.listIterator(index); - } - public T remove(int index) - { - return list.remove(index); - } - public boolean remove(Object o) - { - return list.remove(o); - } - public boolean removeAll(Collection<?> c) - { - return list.removeAll(c); - } - public boolean retainAll(Collection<?> c) - { - return list.retainAll(c); - } - public T set(int index, T element) - { - return list.set(index, element); - } - public int size() - { - return list.size(); - } - public List<T> subList(int fromIndex, int toIndex) - { - return list.subList(fromIndex, toIndex); - } - public Object[] toArray() - { - return list.toArray(); - } - public <X> X[] toArray(X[] a) - { - return list.toArray(a); - } - public void close() - { - } - public void disconnect() - { - } - public boolean isConnected() - { - return false; - } - - } - - private final IProteinQueryDAO dao; - - private final DatabaseConfigurationContext context; - - private final SimpleJdbcTemplate template; - - private NamedParameterJdbcTemplate namedTemplate; - - ProteinQueryDAO(final IProteinQueryDAO dao, DatabaseConfigurationContext context) - { - this.dao = dao; - this.context = context; - template = new SimpleJdbcTemplate(context.getDataSource()); - namedTemplate = new NamedParameterJdbcTemplate(context.getDataSource()); - } - - public void close() - { - dao.close(); - } - - public DataSet<ProbabilityFDRMapping> getProbabilityFDRMapping(long dataSetID) - { - return dao.getProbabilityFDRMapping(dataSetID); - } - - public boolean isClosed() - { - return dao.isClosed(); - } - - public DataSet<String> listAbundanceRelatedSamplePermIDsByExperiment(String experimentPermID) - { - return dao.listAbundanceRelatedSamplePermIDsByExperiment(experimentPermID); - } - - public DataSet<IdentifiedPeptide> listIdentifiedPeptidesByProtein(long proteinID) - { - return dao.listIdentifiedPeptidesByProtein(proteinID); - } - - public DataSet<ProteinReferenceWithProbability> listProteinsByExperiment( - String experimentPermID) - { - long time = System.currentTimeMillis(); - final LobHandler lobHandler = context.getLobHandler(); - List<ProteinReferenceWithProbability> resultSet = - template.queryForObject( - "select blob from protein_view_cache where experiment_perm_id = ?", - new ParameterizedRowMapper<List<ProteinReferenceWithProbability>>() - { - - public List<ProteinReferenceWithProbability> mapRow(ResultSet rs, - int rowNum) throws SQLException - { - return (List<ProteinReferenceWithProbability>) SerializationUtils - .deserialize(lobHandler.getBlobAsBinaryStream(rs, 1)); - } - }, experimentPermID); - operationLog.info("(" + (System.currentTimeMillis() - time) + "ms) listProteinsByExperiment"); - return new DataSetProxy<ProteinReferenceWithProbability>(resultSet); - } - - public DataSet<IdentifiedProtein> listProteinsByProteinReferenceAndExperiment( - String experimentPermID, long proteinReferenceID) - { - return dao.listProteinsByProteinReferenceAndExperiment(experimentPermID, - proteinReferenceID); - } - - public DataSet<Sequence> listProteinSequencesByProteinReference(long proteinReferenceID) - { - return dao.listProteinSequencesByProteinReference(proteinReferenceID); - } - - public DataSet<ProteinReferenceWithProbabilityAndPeptide> listProteinsWithProbabilityAndPeptidesByExperiment( - String experimentPermID) - { - return dao.listProteinsWithProbabilityAndPeptidesByExperiment(experimentPermID); - } - - public DataSet<SampleAbundance> listSampleAbundanceByProtein(String experimentPermID, - long proteinReferenceID) - { - return dao.listSampleAbundanceByProtein(experimentPermID, proteinReferenceID); - } - - public ProteinReference tryToGetProteinReference(long proteinReferenceID) - { - return dao.tryToGetProteinReference(proteinReferenceID); - } - - public byte[] tryToGetCachedProteinView(String experimentPermID) - { - return dao.tryToGetCachedProteinView(experimentPermID); - } - - public DataSet<ProteinReferenceWithProtein> listProteinReferencesByExperiment( - String experimentPermID) - { - long time = System.currentTimeMillis(); - try - { - List<ProteinReferenceWithProtein> list = template.query("select d.id , p.id , probability, coverage, " - + "pr.id, accession_number, description " - + "from protein_references as pr " - + "left join sequences as s on s.prre_id = pr.id " - + "left join identified_proteins as ip on ip.sequ_id = s.id " - + "left join proteins as p on ip.prot_id = p.id " - + "left join data_sets as d on p.dase_id = d.id " - + "left join experiments as e on d.expe_id = e.id where e.perm_id = ?", - new ParameterizedRowMapper<ProteinReferenceWithProtein>() - { - - public ProteinReferenceWithProtein mapRow(ResultSet rs, int rowNum) - throws SQLException - { - ProteinReferenceWithProtein protein = - new ProteinReferenceWithProtein(); - protein.setDataSetID(rs.getLong(1)); - protein.setProteinID(rs.getLong(2)); - protein.setProbability(rs.getDouble(3)); - protein.setCoverage(rs.getDouble(4)); - protein.setId(rs.getLong(5)); - protein.setAccessionNumber(rs.getString(6)); - protein.setDescription(rs.getString(7)); - return protein; - } - }, experimentPermID); - return new DataSetProxy<ProteinReferenceWithProtein>(list); -// return dao.listProteinReferencesByExperiment(experimentPermID); - } finally - { - operationLog.info("(" + (System.currentTimeMillis() - time )+ "ms) listProteinReferenceByExperiment"); - } - } - - public DataSet<ProteinAbundance> listProteinWithAbundanceByExperiment( - LongSet proteinIDs) - { - long time = System.currentTimeMillis(); - try - { - List<ProteinAbundance> list = namedTemplate.query("select p.id, a.value, s.perm_id " - + "from proteins as p join abundances as a on p.id = a.prot_id " - + "left join samples as s on a.samp_id = s.id " - + "where p.id in (:ids)", Collections.singletonMap("ids", proteinIDs), new RowMapper() - { - - public Object mapRow(ResultSet rs, int rowNum) throws SQLException - { - ProteinAbundance proteinAbundance = new ProteinAbundance(); - proteinAbundance.setId(rs.getLong(1)); - proteinAbundance.setAbundance(rs.getDouble(2)); - proteinAbundance.setSampleID(rs.getString(3)); - return proteinAbundance; - } - }); - return new DataSetProxy<ProteinAbundance>(list); - } finally - { - operationLog.info("(" + (System.currentTimeMillis() - time) - + "ms) listProteinWithAbundanceByExperiment"); - } - } - } - - private IProteinQueryDAO proteinQueryDAO; - private DatabaseConfigurationContext context; - - DAOFactoryWithCache(IPhosphoNetXDAOFactory daoFactory, String typeOfCaching) - { - proteinQueryDAO = new ProteinQueryDAO(daoFactory.getProteinQueryDAO(), daoFactory.getContext()); - context = daoFactory.getContext(); - } - - public IProteinQueryDAO getProteinQueryDAO() - { - return proteinQueryDAO; - } - - public DatabaseConfigurationContext getContext() - { - return context; - } - -} diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ErrorModel.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ErrorModel.java index 945ecc7b86a..d1681f9b23d 100644 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ErrorModel.java +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ErrorModel.java @@ -26,7 +26,7 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.dataaccess.IProteinQue import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.ProbabilityToFDRCalculator; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.IdentifiedProtein; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProbabilityFDRMapping; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability; +import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProtein; /** * @author Franz-Josef Elmer @@ -43,7 +43,7 @@ class ErrorModel this.specificDAOFactory = specificDAOFactory; } - boolean passProtein(ProteinReferenceWithProbability protein, double falseDiscoveryRate) + boolean passProtein(ProteinReferenceWithProtein protein, double falseDiscoveryRate) { ProbabilityToFDRCalculator calculator = getCalculator(protein.getDataSetID()); return calculator.calculateFDR(protein.getProbability()) <= falseDiscoveryRate; diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinInfoTable.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinInfoTable.java index 337c15436f4..53bb3ef4fbc 100644 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinInfoTable.java +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinInfoTable.java @@ -38,7 +38,6 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.AbundanceCol import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.AggregateFunction; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.ProteinInfo; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinAbundance; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProtein; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinWithAbundances; @@ -124,91 +123,60 @@ class ProteinInfoTable extends AbstractBusinessObject implements IProteinInfoTab double falseDiscoveryRate) { AbundanceManager abundanceManager = new AbundanceManager(sampleProvider); - IPhosphoNetXDAOFactory daoFactory = getSpecificDAOFactory(); - ErrorModel errorModel = new ErrorModel(daoFactory); - IProteinQueryDAO proteinQueryDAO = daoFactory.getProteinQueryDAO(); - DataSet<ProteinReferenceWithProtein> ds1 = proteinQueryDAO.listProteinReferencesByExperiment(experimentPermID); - List<ProteinReferenceWithProtein> prs = new ArrayList<ProteinReferenceWithProtein>(); + IPhosphoNetXDAOFactory specificDAOFactory = getSpecificDAOFactory(); + IProteinQueryDAO dao = specificDAOFactory.getProteinQueryDAO(); + DataSet<ProteinReferenceWithProtein> dataSet = + dao.listProteinReferencesByExperiment(experimentPermID); + List<ProteinReferenceWithProtein> proteins = new ArrayList<ProteinReferenceWithProtein>(); LongOpenHashSet proteinIDs = new LongOpenHashSet(); try { - for (ProteinReferenceWithProtein protein : ds1) + for (ProteinReferenceWithProtein protein : dataSet) { - prs.add(protein); + proteins.add(protein); proteinIDs.add(protein.getProteinID()); } } finally { - ds1.close(); + dataSet.close(); } - DataSet<ProteinAbundance> ds2 = proteinQueryDAO.listProteinWithAbundanceByExperiment(proteinIDs); - Map<Long, List<ProteinAbundance>> p2a = new HashMap<Long, List<ProteinAbundance>>(); + Map<Long, List<ProteinAbundance>> abundancesPerProtein = getAbudancesPerProtein(proteinIDs); + ErrorModel errorModel = new ErrorModel(specificDAOFactory); + for (ProteinReferenceWithProtein protein : proteins) + { + if (errorModel.passProtein(protein, falseDiscoveryRate)) + { + List<ProteinAbundance> list = abundancesPerProtein.get(protein.getProteinID()); + abundanceManager.handle(protein, list); + } + } + return abundanceManager; + } + + private Map<Long, List<ProteinAbundance>> getAbudancesPerProtein(LongOpenHashSet proteinIDs) + { + IProteinQueryDAO dao = getSpecificDAOFactory().getProteinQueryDAO(); + DataSet<ProteinAbundance> dataSet = dao.listProteinWithAbundanceByExperiment(proteinIDs); + Map<Long, List<ProteinAbundance>> abundancesPerProtein = + new HashMap<Long, List<ProteinAbundance>>(); try { - for (ProteinAbundance proteinAbundance : ds2) + for (ProteinAbundance proteinAbundance : dataSet) { long proteinID = proteinAbundance.getId(); - List<ProteinAbundance> list = p2a.get(proteinID); + List<ProteinAbundance> list = abundancesPerProtein.get(proteinID); if (list == null) { list = new ArrayList<ProteinAbundance>(); - p2a.put(proteinID, list); + abundancesPerProtein.put(proteinID, list); } list.add(proteinAbundance); } } finally { - ds2.close(); - } - for (ProteinReferenceWithProtein proteinReferenceWithProtein : prs) - { - ProteinReferenceWithProbability protein = translate(proteinReferenceWithProtein); - if (errorModel.passProtein(protein, falseDiscoveryRate)) - { - List<ProteinAbundance> list = p2a.get(proteinReferenceWithProtein.getProteinID()); - if (list == null) - { - abundanceManager.handle(protein); - } else - { - for (ProteinAbundance proteinAbundance : list) - { - protein.setAbundance(proteinAbundance.getAbundance()); - protein.setSamplePermID(proteinAbundance.getSamplePermID()); - abundanceManager.handle(protein); - } - } - } + dataSet.close(); } -// DataSet<ProteinReferenceWithProbability> resultSet = -// proteinQueryDAO.listProteinsByExperiment(experimentPermID); -// try -// { -// for (ProteinReferenceWithProbability protein : resultSet) -// { -// if (errorModel.passProtein(protein, falseDiscoveryRate)) -// { -// abundanceManager.handle(protein); -// } -// } -// } finally -// { -// resultSet.close(); -// } - return abundanceManager; - } - - private ProteinReferenceWithProbability translate( - ProteinReferenceWithProtein proteinReferenceWithProtein) - { - ProteinReferenceWithProbability proteinReferenceWithProbability = new ProteinReferenceWithProbability(); - proteinReferenceWithProbability.setId(proteinReferenceWithProtein.getId()); - proteinReferenceWithProbability.setAccessionNumber(proteinReferenceWithProtein.getAccessionNumber()); - proteinReferenceWithProbability.setDescription(proteinReferenceWithProtein.getDescription()); - proteinReferenceWithProbability.setCoverage(proteinReferenceWithProtein.getCoverage()); - proteinReferenceWithProbability.setProbability(proteinReferenceWithProtein.getProbability()); - proteinReferenceWithProbability.setDataSetID(proteinReferenceWithProtein.getDataSetID()); - return proteinReferenceWithProbability; + return abundancesPerProtein; } private static double[] concatenate(double[] array1OrNull, double[] array2OrNull) diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/dataaccess/IProteinQueryDAO.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/dataaccess/IProteinQueryDAO.java index 2e5a22a4d42..3eb157ccf0c 100644 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/dataaccess/IProteinQueryDAO.java +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/dataaccess/IProteinQueryDAO.java @@ -28,7 +28,6 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.IdentifiedProtein; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProbabilityFDRMapping; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinAbundance; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReference; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbabilityAndPeptide; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProtein; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.SampleAbundance; @@ -44,9 +43,6 @@ public interface IProteinQueryDAO extends BaseQuery @Select(sql = "select * from probability_fdr_mappings where dase_id = ?{1}", disconnected = true) public DataSet<ProbabilityFDRMapping> getProbabilityFDRMapping(long dataSetID); - @Select("select blob from protein_view_cache where experiment_perm_id = ?{1}") - public byte[] tryToGetCachedProteinView(String experimentPermID); - @Select("select d.id as data_set_id, p.id as protein_id, probability, coverage, " + "pr.id, accession_number, description from protein_references as pr " + "left join sequences as s on s.prre_id = pr.id " @@ -63,19 +59,6 @@ public interface IProteinQueryDAO extends BaseQuery + "where p.id = any (?{1})", parameterBindings = { LongSetMapper.class }) public DataSet<ProteinAbundance> listProteinWithAbundanceByExperiment(LongSet proteinIDs); - @Select("select pr.id, pr.accession_number, pr.description, d.id as data_set_id, p.probability, " - + " ip.coverage, a.value as abundance, samples.perm_id as sample_perm_id " - + "from identified_proteins as ip left join proteins as p on ip.prot_id = p.id " - + "left join data_sets as d on p.dase_id = d.id " - + "left join experiments as e on d.expe_id = e.id " - + "left join sequences as s on ip.sequ_id = s.id " - + "left join protein_references as pr on s.prre_id = pr.id " - + "left join abundances as a on p.id = a.prot_id " - + "left join samples on a.samp_id = samples.id " - + "where e.perm_id = ?{1}") - public DataSet<ProteinReferenceWithProbability> listProteinsByExperiment(String experimentPermID); - - @Select(sql = "select p.dase_id as data_set_id, p.probability, s.prre_id as id, pe.sequence " + "from identified_proteins as ip left join sequences as s on ip.sequ_id = s.id " + "left join proteins as p on ip.prot_id = p.id " diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/dataaccess/db/migration/MigrationStepFrom002To003.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/dataaccess/db/migration/MigrationStepFrom002To003.java index 7439043104d..ec250df1430 100644 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/dataaccess/db/migration/MigrationStepFrom002To003.java +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/dataaccess/db/migration/MigrationStepFrom002To003.java @@ -16,9 +16,6 @@ package ch.systemsx.cisd.openbis.plugin.phosphonetx.server.dataaccess.db.migration; -import java.io.ByteArrayOutputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; @@ -28,23 +25,17 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.lang.SerializationUtils; import org.apache.log4j.Logger; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.JdbcOperations; import org.springframework.jdbc.core.ResultSetExtractor; -import org.springframework.jdbc.core.simple.ParameterizedRowMapper; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; -import org.springframework.jdbc.support.JdbcUtils; - -import sun.print.PSPrinterJob.EPSPrinter; import ch.systemsx.cisd.common.logging.LogCategory; import ch.systemsx.cisd.common.logging.LogFactory; import ch.systemsx.cisd.dbmigration.java.MigrationStepAdapter; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.Occurrence; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.OccurrenceUtil; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability; /** * @@ -64,7 +55,6 @@ public class MigrationStepFrom002To003 extends MigrationStepAdapter List<Object[]> coverageValues = calculateCoverageValues(simpleJdbcTemplate); operationLog.info("update " + coverageValues.size() + " identified proteins"); simpleJdbcTemplate.batchUpdate("update identified_proteins set coverage = ? where id = ?", coverageValues); - createProteinView(simpleJdbcTemplate); } private List<Object[]> calculateCoverageValues(SimpleJdbcTemplate simpleJdbcTemplate) @@ -99,67 +89,6 @@ public class MigrationStepFrom002To003 extends MigrationStepAdapter return values; } - private void createProteinView(SimpleJdbcTemplate simpleJdbcTemplate) - { - List<String> experiments = - simpleJdbcTemplate.query("select perm_id from experiments", - new ParameterizedRowMapper<String>() - { - public String mapRow(ResultSet rs, int rowNum) throws SQLException - { - return rs.getString(1); - } - }); - operationLog.info("create protein views for " + experiments.size() + " experiments"); - logMemory(); - JdbcOperations jdbcOperations = simpleJdbcTemplate.getJdbcOperations(); - Object[] arguments = new Object[1]; - for (final String experiment : experiments) - { - arguments[0] = experiment; - List<ProteinReferenceWithProbability> rows = simpleJdbcTemplate.query( - "select pr.id, pr.accession_number, pr.description, d.id, p.probability, " - + "ip.coverage, a.value, samples.perm_id " - + "from identified_proteins as ip " - + "left join proteins as p on ip.prot_id = p.id " - + "left join data_sets as d on p.dase_id = d.id " - + "left join experiments as e on d.expe_id = e.id " - + "left join sequences as s on ip.sequ_id = s.id " - + "left join protein_references as pr on s.prre_id = pr.id " - + "left join abundances as a on p.id = a.prot_id " - + "left join samples on a.samp_id = samples.id " - + "where e.perm_id = ?", new ParameterizedRowMapper<ProteinReferenceWithProbability>() - { - - public ProteinReferenceWithProbability mapRow(ResultSet rs, - int rowNum) throws SQLException - { - ProteinReferenceWithProbability protein = new ProteinReferenceWithProbability(); - protein.setId(rs.getLong(1)); - protein.setAccessionNumber(rs.getString(2)); - protein.setDescription(rs.getString(3)); - protein.setDataSetID(rs.getLong(4)); - protein.setProbability(rs.getDouble(5)); - protein.setCoverage(rs.getDouble(6)); - protein.setAbundance(getDoubleOrNull(rs, 7)); - protein.setSamplePermID(rs.getString(8)); - return protein; - } - }, experiment); - operationLog.info("insert " + rows.size() + " rows into protein_view_cache for experiment " - + experiment); - byte[] serializedRows = SerializationUtils.serialize((Serializable) rows); - simpleJdbcTemplate.update("insert into protein_view_cache (experiment_perm_id, blob) " - + "values(?, ?)", experiment, serializedRows); - logMemory(); - } - } - private Double getDoubleOrNull(ResultSet rs, int index) throws SQLException - { - double result = rs.getDouble(index); - return rs.wasNull() ? null : result; - } - private Map<Long, List<String>> getPeptides(JdbcOperations jdbcOperations) { final Map<Long, List<String>> peptides = new HashMap<Long, List<String>>(); diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/dto/ProteinWithAbundances.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/dto/ProteinWithAbundances.java index 8a16a8f4bbe..4888189e7a8 100644 --- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/dto/ProteinWithAbundances.java +++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/shared/dto/ProteinWithAbundances.java @@ -16,6 +16,8 @@ package ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto; +import it.unimi.dsi.fastutil.doubles.DoubleArrayList; + import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; @@ -33,7 +35,7 @@ public class ProteinWithAbundances extends ProteinReference private double coverage; - private final Map<Long, double[]> abundances = new LinkedHashMap<Long, double[]>(); + private final Map<Long, DoubleArrayList> abundances = new LinkedHashMap<Long, DoubleArrayList>(); public double getCoverage() { @@ -47,15 +49,13 @@ public class ProteinWithAbundances extends ProteinReference public void addAbundanceFor(long sampleID, double abundance) { - double[] array = abundances.get(sampleID); - if (array == null) + DoubleArrayList list = abundances.get(sampleID); + if (list == null) { - array = EMPTY_ARRAY; + list = new DoubleArrayList(); + abundances.put(sampleID, list); } - double[] newArray = new double[array.length + 1]; - System.arraycopy(array, 0, newArray, 0, array.length); - newArray[array.length] = abundance; - abundances.put(sampleID, newArray); + list.add(abundance); } public Set<Long> getSampleIDs() @@ -65,7 +65,7 @@ public class ProteinWithAbundances extends ProteinReference public double[] getAbundancesForSample(long sampleID) { - double[] values = abundances.get(sampleID); - return values == null ? EMPTY_ARRAY : values; + DoubleArrayList list = abundances.get(sampleID); + return list == null ? EMPTY_ARRAY : list.toDoubleArray(); } } diff --git a/rtd_phosphonetx/source/java/phosphonetx-applicationContext.xml b/rtd_phosphonetx/source/java/phosphonetx-applicationContext.xml index f07dc588873..6014a32b9ae 100644 --- a/rtd_phosphonetx/source/java/phosphonetx-applicationContext.xml +++ b/rtd_phosphonetx/source/java/phosphonetx-applicationContext.xml @@ -20,7 +20,7 @@ <property name="urlHostPart" value="${phosphonetx.database.url-host-part}" /> <property name="adminUser" value="${phosphonetx.database.admin-user}" /> <property name="owner" value="${phosphonetx.database.owner}" /> - <property name="readOnlyGroup" value="openbis_readonly" /> + <property name="readOnlyGroup" value="phosphonetx_readonly" /> <property name="password" value="${phosphonetx.database.owner-password}" /> <property name="adminPassword" value="${phosphonetx.database.admin-password}" /> <property name="databaseKind" value="${phosphonetx.database.kind}" /> @@ -38,7 +38,6 @@ class="ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business.BusinessObjectFactory"> <constructor-arg ref="dao-factory"/> <constructor-arg ref="phosphonetx-dao-factory"/> - <constructor-arg value="${type-of-caching}"/> </bean> <!-- diff --git a/rtd_phosphonetx/source/java/service.properties b/rtd_phosphonetx/source/java/service.properties index 05992f1a344..15fd9cc901b 100644 --- a/rtd_phosphonetx/source/java/service.properties +++ b/rtd_phosphonetx/source/java/service.properties @@ -66,5 +66,3 @@ query-database.label = Protein Data query-database.databaseEngineCode = ${phosphonetx.database.engine} query-database.basicDatabaseName = phosphonetx query-database.databaseKind = ${phosphonetx.database.kind} - -#type-of-caching = file_system \ No newline at end of file diff --git a/rtd_phosphonetx/source/sql/postgresql/003/grant-003.sql b/rtd_phosphonetx/source/sql/postgresql/003/grant-003.sql new file mode 100644 index 00000000000..2e85f4fb1f6 --- /dev/null +++ b/rtd_phosphonetx/source/sql/postgresql/003/grant-003.sql @@ -0,0 +1,18 @@ +-- Granting SELECT privilege to group PHOSPHONETX_READONLY + +GRANT SELECT ON TABLE EXPERIMENTS TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE DATA_SETS TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE MODIFICATIONS TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE PEPTIDES TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE PROTEINS TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE SAMPLES TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE SEQUENCES TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE IDENTIFIED_PROTEINS TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE ABUNDANCES TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE PROBABILITY_FDR_MAPPINGS TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE PROTEIN_REFERENCES TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE DATABASES TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE MODIFIED_PEPTIDES TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE SPECTRUM_REFERENCES TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE MODIFICATION_FRACTIONS TO GROUP PHOSPHONETX_READONLY; +GRANT SELECT ON TABLE EVENTS TO GROUP PHOSPHONETX_READONLY; diff --git a/rtd_phosphonetx/source/sql/postgresql/003/schema-003.png b/rtd_phosphonetx/source/sql/postgresql/003/schema-003.png new file mode 100755 index 0000000000000000000000000000000000000000..da8cae484122317fee9b24a68fa70670bec52989 GIT binary patch literal 65092 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%0AroZ+nl28U+e+e`S~FWQ}orQXeZwvNFBfb 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 R%Y%SFSxF^{axvrg{|o2d2D|_O literal 0 HcmV?d00001 diff --git a/rtd_phosphonetx/source/sql/postgresql/003/schema-003.sql b/rtd_phosphonetx/source/sql/postgresql/003/schema-003.sql index 1c4cf2041d7..4dd90b2711c 100755 --- a/rtd_phosphonetx/source/sql/postgresql/003/schema-003.sql +++ b/rtd_phosphonetx/source/sql/postgresql/003/schema-003.sql @@ -5,8 +5,8 @@ /* Project name: */ /* Author: */ /* Script type: Database creation script */ -/* Created on: 2009-12-07 11:03 */ -/* Model version: Version 2009-12-07 */ +/* Created on: 2010-03-31 16:10 */ +/* Model version: Version 2010-03-31 */ /* ---------------------------------------------------------------------- */ @@ -40,18 +40,6 @@ CREATE DOMAIN SPECTRUM_REFERENCE AS CHARACTER VARYING(100); /* Tables */ /* ---------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------- */ -/* Add table "PROTEIN_VIEW" */ -/* ---------------------------------------------------------------------- */ - -CREATE TABLE PROTEIN_VIEW_CACHE ( - ID BIGSERIAL NOT NULL, - EXPERIMENT_PERM_ID CODE NOT NULL, - BLOB BYTEA NOT NULL, - CONSTRAINT PK_PROTEIN_VIEW PRIMARY KEY (ID) -); - - /* ---------------------------------------------------------------------- */ /* Add table "EXPERIMENTS" */ /* ---------------------------------------------------------------------- */ diff --git a/rtd_phosphonetx/source/sql/postgresql/migration/migration-002-003.sql b/rtd_phosphonetx/source/sql/postgresql/migration/migration-002-003.sql index f2f9b1ecea6..639f94657a5 100644 --- a/rtd_phosphonetx/source/sql/postgresql/migration/migration-002-003.sql +++ b/rtd_phosphonetx/source/sql/postgresql/migration/migration-002-003.sql @@ -2,10 +2,3 @@ ALTER TABLE IDENTIFIED_PROTEINS ADD COLUMN COVERAGE REAL_NUMBER; -CREATE TABLE PROTEIN_VIEW_CACHE ( - ID BIGSERIAL NOT NULL, - EXPERIMENT_PERM_ID CODE NOT NULL, - BLOB BYTEA NOT NULL, - CONSTRAINT PK_PROTEIN_VIEW PRIMARY KEY (ID) -); - diff --git a/rtd_phosphonetx/source/sql/postgresql/schema.dez b/rtd_phosphonetx/source/sql/postgresql/schema.dez index db19fe66275..f7c4d30fd33 100755 --- a/rtd_phosphonetx/source/sql/postgresql/schema.dez +++ b/rtd_phosphonetx/source/sql/postgresql/schema.dez @@ -4,14 +4,14 @@ <VERSION> <PROJECTSETTINGS> <PROJECTFILENAME>D:\User\felmer\dev-workspace\rtd_phosphonetx\source\sql\postgresql\phosphonetx.dez</PROJECTFILENAME> -<MODIFIED>2009-12-07</MODIFIED> +<MODIFIED>2010-03-31</MODIFIED> <CREATED>2009-06-29</CREATED> <CREATED2></CREATED2> <PROJECTNAME></PROJECTNAME> <DESCRIPTION></DESCRIPTION> <AUTHOR></AUTHOR> <COPYRIGHT></COPYRIGHT> -<LASTGENERATEDFILES>N:\group\cisd\phosphonetx\datamodel\schema.sql;N:\group\cisd\phosphonetx\datamodel\drop.sql;C:\Users\felmer\Documents\CreateDBLog_200912073.txt</LASTGENERATEDFILES> +<LASTGENERATEDFILES>N:\group\cisd\phosphonetx\datamodel\schema.sql;N:\group\cisd\phosphonetx\datamodel\drop.sql;\\d.ethz.ch\dfs\groups\bsse\users\cisd\felmer\Documents\CreateDBLog_201003311.txt</LASTGENERATEDFILES> </PROJECTSETTINGS> <CONNECTIONSETTINGS> <SQLFILE>D:\User\felmer\dev-workspace\rtd_phosphonetx\source\sql\postgresql\001\schema-001.sql</SQLFILE> @@ -1209,7 +1209,7 @@ <POSNR>0</POSNR> <SCHEMA></SCHEMA> <DESC></DESC> -<ATTRLASTID>5</ATTRLASTID> +<ATTRLASTID>6</ATTRLASTID> <IDXLASTID>1</IDXLASTID> <TRGLASTID>1</TRGLASTID> <CONLASTID>1</CONLASTID> @@ -1309,6 +1309,19 @@ </ATTRIBUTEIDS> </NNCON> </ATTR> +<ATTR> +<NAME>COVERAGE</NAME> +<ID>6</ID> +<POSNR>0</POSNR> +<SCHEMA></SCHEMA> +<DESC></DESC> +<DOMAINID>8</DOMAINID> +<DT> +<DTLISTNAME>DOUBLE PRECISION</DTLISTNAME> +<SD>0</SD> +<INC>1</INC> +</DT> +</ATTR> </ATTRIBUTES> </ENT> <ENT> @@ -2194,6 +2207,7 @@ </ENT> <ENT> <NAME>EVENTS</NAME> +<NAMETEMPLATE>NN_%column%</NAMETEMPLATE> <ID>176</ID> <POSNR>0</POSNR> <SCHEMA></SCHEMA> @@ -2205,6 +2219,7 @@ <ATTRIBUTES> <ATTR> <NAME>LAST_SEEN_DELETION_EVENT_ID</NAME> +<NAMETEMPLATE>NN_%column%</NAMETEMPLATE> <ID>2</ID> <POSNR>0</POSNR> <SCHEMA></SCHEMA> @@ -3061,9 +3076,9 @@ <ENTC> <ID>47</ID> <DIAGRAMID>1</DIAGRAMID> -<W>142</W> -<H>78</H> -<L>541</L> +<W>167</W> +<H>93</H> +<L>518</L> <T>328</T> <BRUSH>0,16777215</BRUSH> <PEN>0,1,4,0</PEN> @@ -3087,7 +3102,7 @@ <ENTC> <ID>96</ID> <DIAGRAMID>1</DIAGRAMID> -<W>245</W> +<W>243</W> <H>93</H> <L>490</L> <T>182</T> @@ -3305,7 +3320,7 @@ <FROMRELATIVEX>5000</FROMRELATIVEX> <FROMRELATIVEY>5000</FROMRELATIVEY> <TORELATIVEX>5000</TORELATIVEX> -<TORELATIVEY>5000</TORELATIVEY> +<TORELATIVEY>4194</TORELATIVEY> <POINTS> <POINT> <X>454</X> @@ -3320,7 +3335,7 @@ <Y>367</Y> </POINT> <POINT> -<X>540</X> +<X>517</X> <Y>367</Y> </POINT> </POINTS> @@ -3331,25 +3346,25 @@ <FONT>Arial,8,,0,clWindowText,0</FONT> <PEN>1,1,4,0</PEN> <FROMRELATIVEX>2840</FROMRELATIVEX> -<FROMRELATIVEY>3611</FROMRELATIVEY> +<FROMRELATIVEY>4259</FROMRELATIVEY> <TORELATIVEX>5000</TORELATIVEX> -<TORELATIVEY>5000</TORELATIVEY> +<TORELATIVEY>4946</TORELATIVEY> <POINTS> <POINT> <X>735</X> -<Y>367</Y> +<Y>374</Y> </POINT> <POINT> -<X>705</X> -<Y>367</Y> +<X>722</X> +<Y>374</Y> </POINT> <POINT> -<X>705</X> -<Y>367</Y> +<X>722</X> +<Y>374</Y> </POINT> <POINT> -<X>683</X> -<Y>367</Y> +<X>685</X> +<Y>374</Y> </POINT> </POINTS> </RELC> diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManagerTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManagerTest.java index 99d399a15d4..9c1b081cfd1 100644 --- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManagerTest.java +++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManagerTest.java @@ -16,7 +16,9 @@ package ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import org.jmock.Expectations; @@ -25,7 +27,8 @@ import org.testng.annotations.Test; import ch.systemsx.cisd.openbis.generic.shared.AbstractServerTestCase; import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability; +import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinAbundance; +import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProtein; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinWithAbundances; /** @@ -64,18 +67,19 @@ public class AbundanceManagerTest extends AbstractServerTestCase public void testHandleTwoProteinReferencesButOnlyOneHasAnAbundance() { prepareSampleIDProvider(); - ProteinReferenceWithProbability protein1 = new ProteinReferenceWithProbability(); + ProteinReferenceWithProtein protein1 = new ProteinReferenceWithProtein(); protein1.setId(1); protein1.setAccessionNumber("abc1"); protein1.setDescription("abc one"); - protein1.setSamplePermID(PERM_ID1); - protein1.setAbundance(1.5); - abundanceManager.handle(protein1); - ProteinReferenceWithProbability protein2 = new ProteinReferenceWithProbability(); + ProteinAbundance proteinAbundance = new ProteinAbundance(); + proteinAbundance.setSampleID(PERM_ID1); + proteinAbundance.setAbundance(1.5); + abundanceManager.handle(protein1, Collections.singletonList(proteinAbundance)); + ProteinReferenceWithProtein protein2 = new ProteinReferenceWithProtein(); protein2.setId(2); protein2.setAccessionNumber("abc2"); protein2.setDescription("abc two"); - abundanceManager.handle(protein2); + abundanceManager.handle(protein2, null); assertEquals(1, abundanceManager.getSampleIDs().size()); Collection<ProteinWithAbundances> proteinsWithAbundances = abundanceManager.getProteinsWithAbundances(); @@ -103,11 +107,13 @@ public class AbundanceManagerTest extends AbstractServerTestCase public void testHandleProteinReferencesWithManyAbundancesForTwoSamples() { prepareSampleIDProvider(); - abundanceManager.handle(createProteinReference(PERM_ID1, 1.5)); - abundanceManager.handle(createProteinReference(PERM_ID1, 2.25)); - abundanceManager.handle(createProteinReference(PERM_ID2, 42)); - abundanceManager.handle(createProteinReference(PERM_ID2, 4.75)); - abundanceManager.handle(createProteinReference(PERM_ID2, 7.5)); + ProteinReferenceWithProtein protein1 = new ProteinReferenceWithProtein(); + protein1.setId(1); + protein1.setAccessionNumber("abc1"); + protein1.setDescription("abc one"); + + abundanceManager.handle(protein1, Arrays.asList(a(PERM_ID1, 1.5), a(PERM_ID1, 2.25), a( + PERM_ID2, 42), a(PERM_ID2, 4.75), a(PERM_ID2, 7.5))); assertEquals(2, abundanceManager.getSampleIDs().size()); Collection<ProteinWithAbundances> proteinsWithAbundances = abundanceManager.getProteinsWithAbundances(); @@ -150,14 +156,11 @@ public class AbundanceManagerTest extends AbstractServerTestCase }); } - private ProteinReferenceWithProbability createProteinReference(String samplePermID, double abundance) + private ProteinAbundance a(String samplePermID, double abundance) { - ProteinReferenceWithProbability protein1 = new ProteinReferenceWithProbability(); - protein1.setId(1); - protein1.setAccessionNumber("abc1"); - protein1.setDescription("abc one"); - protein1.setSamplePermID(samplePermID); - protein1.setAbundance(abundance); - return protein1; + ProteinAbundance protein = new ProteinAbundance(); + protein.setSampleID(samplePermID); + protein.setAbundance(abundance); + return protein; } } diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinInfoTableTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinInfoTableTest.java index 04c35faf6ca..6e2d588865e 100644 --- a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinInfoTableTest.java +++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinInfoTableTest.java @@ -16,11 +16,16 @@ package ch.systemsx.cisd.openbis.plugin.phosphonetx.server.business; +import it.unimi.dsi.fastutil.longs.LongArraySet; +import it.unimi.dsi.fastutil.longs.LongSet; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Map; +import net.lemnik.eodsql.DataSet; + import org.jmock.Expectations; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -36,14 +41,14 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.AbundanceCol import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.AggregateFunction; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.dto.ProteinInfo; import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProbabilityFDRMapping; -import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability; +import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinAbundance; +import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProtein; /** * * * @author Franz-Josef Elmer */ -@Test(groups="broken") public class ProteinInfoTableTest extends AbstractServerTestCase { private static final double COVERAGE = 0.5; @@ -52,7 +57,8 @@ public class ProteinInfoTableTest extends AbstractServerTestCase private static final long SAMPLE_ID_2 = 102L; private static final long SAMPLE_ID_1 = 101L; private static final Double ABUNDANCE = new Double(47.11); - private static final long PROTEIN_ID = 41L; + private static final long PROTEIN_ID = 4141L; + private static final long PROTEIN_REFERENCE_ID = 41L; private static final String SAMPLE_PERM_ID = "s47-11"; private static final long SAMPLE_ID = 4711; private static final long DATA_SET_ID = 42L; @@ -101,42 +107,50 @@ public class ProteinInfoTableTest extends AbstractServerTestCase @Test public void testLoadLeadingToAnEmptyTable() { - final MockDataSet<ProteinReferenceWithProbability> dataSet = - new MockDataSet<ProteinReferenceWithProbability>(); - prepareLoadDataSet(dataSet); + MockDataSet<ProteinReferenceWithProtein> proteinReferences = new MockDataSet<ProteinReferenceWithProtein>(); + MockDataSet<ProteinAbundance> proteinAbundances = new MockDataSet<ProteinAbundance>(); + prepareLoadDataSet(proteinReferences, proteinAbundances); table.load(Arrays.<AbundanceColumnDefinition> asList(), EXPERIMENT_ID, FALSE_DISCOVERY_RATE, AggregateFunction.MEAN, false); assertEquals(0, table.getProteinInfos().size()); - assertEquals(true, dataSet.hasCloseBeenInvoked()); + assertEquals(true, proteinReferences.hasCloseBeenInvoked()); + assertEquals(true, proteinAbundances.hasCloseBeenInvoked()); context.assertIsSatisfied(); } @Test public void testSimpleLoad() { - final MockDataSet<ProteinReferenceWithProbability> dataSet = - new MockDataSet<ProteinReferenceWithProbability>(); - ProteinReferenceWithProbability proteinReference = new ProteinReferenceWithProbability(); + MockDataSet<ProteinReferenceWithProtein> proteinReferences = + new MockDataSet<ProteinReferenceWithProtein>(); + MockDataSet<ProteinAbundance> abundances = new MockDataSet<ProteinAbundance>(); + ProteinReferenceWithProtein proteinReference = new ProteinReferenceWithProtein(); proteinReference.setDataSetID(DATA_SET_ID); - proteinReference.setSamplePermID(SAMPLE_PERM_ID); + proteinReference.setProteinID(PROTEIN_ID); proteinReference.setAccessionNumber(ACCESSION_NUMBER); - proteinReference.setId(PROTEIN_ID); - proteinReference.setAbundance(ABUNDANCE); - dataSet.add(proteinReference); - proteinReference = new ProteinReferenceWithProbability(); + proteinReference.setId(PROTEIN_REFERENCE_ID); + proteinReferences.add(proteinReference); + ProteinAbundance proteinAbundance = new ProteinAbundance(); + proteinAbundance.setId(PROTEIN_ID); + proteinAbundance.setAbundance(ABUNDANCE); + proteinAbundance.setSampleID(SAMPLE_PERM_ID); + abundances.add(proteinAbundance); + proteinReference = new ProteinReferenceWithProtein(); + proteinReference.setProteinID(PROTEIN_ID); + proteinReference.setId(PROTEIN_REFERENCE_ID); proteinReference.setProbability(1); proteinReference.setDataSetID(DATA_SET_ID); - dataSet.add(proteinReference); + proteinReferences.add(proteinReference); final MockDataSet<ProbabilityFDRMapping> mappings = new MockDataSet<ProbabilityFDRMapping>(); mappings.add(new ProbabilityFDRMapping()); ProbabilityFDRMapping mapping = new ProbabilityFDRMapping(); mapping.setProbability(1); mapping.setFalseDiscoveryRate(1); mappings.add(mapping); - prepareLoadDataSet(dataSet); + prepareLoadDataSet(proteinReferences, abundances); context.checking(new Expectations() { { @@ -158,10 +172,10 @@ public class ProteinInfoTableTest extends AbstractServerTestCase Collection<ProteinInfo> proteins = table.getProteinInfos(); assertEquals(1, proteins.size()); ProteinInfo protein = proteins.iterator().next(); - assertEquals(PROTEIN_ID, protein.getId().getId().longValue()); + assertEquals(PROTEIN_REFERENCE_ID, protein.getId().getId().longValue()); assertEquals(ACCESSION_NUMBER, protein.getAccessionNumber()); - assertEquals(true, dataSet.hasCloseBeenInvoked()); + assertEquals(true, proteinReferences.hasCloseBeenInvoked()); assertEquals(true, mappings.hasCloseBeenInvoked()); context.assertIsSatisfied(); } @@ -180,19 +194,27 @@ public class ProteinInfoTableTest extends AbstractServerTestCase private void checkAggregationType(double expectedAbundance, boolean aggregateOriginal) { - final MockDataSet<ProteinReferenceWithProbability> dataSet = - new MockDataSet<ProteinReferenceWithProbability>(); - dataSet.add(createProtein(SAMPLE_ID_1, 1)); - dataSet.add(createProtein(SAMPLE_ID_1, 2)); - dataSet.add(createProtein(SAMPLE_ID_2, 3)); - dataSet.add(createProtein(SAMPLE_ID_3, 20)); + final MockDataSet<ProteinReferenceWithProtein> proteinReferences = + new MockDataSet<ProteinReferenceWithProtein>(); + ProteinReferenceWithProtein proteinReference = new ProteinReferenceWithProtein(); + proteinReference.setProteinID(PROTEIN_ID); + proteinReference.setDataSetID(DATA_SET_ID); + proteinReference.setAccessionNumber(ACCESSION_NUMBER); + proteinReference.setId(PROTEIN_REFERENCE_ID); + proteinReference.setCoverage(COVERAGE); + proteinReferences.add(proteinReference); + MockDataSet<ProteinAbundance> proteinAbundances = new MockDataSet<ProteinAbundance>(); + proteinAbundances.add(createProteinAbundance(SAMPLE_ID_1, 1)); + proteinAbundances.add(createProteinAbundance(SAMPLE_ID_1, 2)); + proteinAbundances.add(createProteinAbundance(SAMPLE_ID_2, 3)); + proteinAbundances.add(createProteinAbundance(SAMPLE_ID_3, 20)); final MockDataSet<ProbabilityFDRMapping> mappings = new MockDataSet<ProbabilityFDRMapping>(); mappings.add(new ProbabilityFDRMapping()); ProbabilityFDRMapping mapping = new ProbabilityFDRMapping(); mapping.setProbability(1); mapping.setFalseDiscoveryRate(1); mappings.add(mapping); - prepareLoadDataSet(dataSet); + prepareLoadDataSet(proteinReferences, proteinAbundances); context.checking(new Expectations() { { @@ -215,7 +237,7 @@ public class ProteinInfoTableTest extends AbstractServerTestCase Collection<ProteinInfo> proteins = table.getProteinInfos(); assertEquals(1, proteins.size()); ProteinInfo protein = proteins.iterator().next(); - assertEquals(PROTEIN_ID, protein.getId().getId().longValue()); + assertEquals(PROTEIN_REFERENCE_ID, protein.getId().getId().longValue()); assertEquals(ACCESSION_NUMBER, protein.getAccessionNumber()); Map<Long, Double> abundances = protein.getAbundances(); assertEquals(2, abundances.size()); @@ -223,12 +245,14 @@ public class ProteinInfoTableTest extends AbstractServerTestCase assertEquals(20.0, abundances.get(SAMPLE_ID_3).doubleValue()); assertEquals(100 * COVERAGE, protein.getCoverage()); - assertEquals(true, dataSet.hasCloseBeenInvoked()); + assertEquals(true, proteinReferences.hasCloseBeenInvoked()); assertEquals(true, mappings.hasCloseBeenInvoked()); context.assertIsSatisfied(); } - private void prepareLoadDataSet(final MockDataSet<ProteinReferenceWithProbability> dataSet) + private void prepareLoadDataSet( + final MockDataSet<ProteinReferenceWithProtein> proteinReferences, + final DataSet<ProteinAbundance> proteinAbundances) { context.checking(new Expectations() { @@ -238,22 +262,27 @@ public class ProteinInfoTableTest extends AbstractServerTestCase experimentPE.setPermId(EXPERIMENT_PERM_ID); will(returnValue(experimentPE)); - one(proteinDAO).listProteinsByExperiment(EXPERIMENT_PERM_ID); - will(returnValue(dataSet)); + one(proteinDAO).listProteinReferencesByExperiment(EXPERIMENT_PERM_ID); + will(returnValue(proteinReferences)); + + LongSet proteinIDs = new LongArraySet(); + for (ProteinReferenceWithProtein p : proteinReferences) + { + proteinIDs.add(p.getProteinID()); + } + one(proteinDAO).listProteinWithAbundanceByExperiment(proteinIDs); + will(returnValue(proteinAbundances)); } }); } - private ProteinReferenceWithProbability createProtein(long sampleID, double abundance) + private ProteinAbundance createProteinAbundance(long sampleID, double abundance) { - ProteinReferenceWithProbability proteinReference = new ProteinReferenceWithProbability(); - proteinReference.setDataSetID(DATA_SET_ID); - proteinReference.setSamplePermID(PERM_ID_PREFIX + sampleID); - proteinReference.setAccessionNumber(ACCESSION_NUMBER); - proteinReference.setId(PROTEIN_ID); - proteinReference.setAbundance(abundance); - proteinReference.setCoverage(COVERAGE); - return proteinReference; + ProteinAbundance proteinAbundance = new ProteinAbundance(); + proteinAbundance.setSampleID(PERM_ID_PREFIX + sampleID); + proteinAbundance.setId(PROTEIN_ID); + proteinAbundance.setAbundance(abundance); + return proteinAbundance; } } -- GitLab