From 0ca782e172ece181e460dd8ae6883f852411ec5d Mon Sep 17 00:00:00 2001
From: felmer <felmer>
Date: Tue, 5 Apr 2011 09:41:19 +0000
Subject: [PATCH] LMS-2174 feeding database with modification fractions

SVN: 20652
---
 .../phosphonetx/AbstractHandler.java          |  16 +--
 .../phosphonetx/AbstractSampleHandler.java    | 129 ++++++++++++++++++
 .../phosphonetx/AbundanceHandler.java         | 108 +++------------
 .../etlserver/phosphonetx/IProtDAO.java       |   7 +-
 .../phosphonetx/ModificationFraction.java     |  85 ++++++++++++
 .../ModificationFractionHandler.java          |  69 ++++++++++
 .../phosphonetx/ResultDataSetUploader.java    |  91 +++++++++++-
 .../phosphonetx/dto/AminoAcidMass.java        |  21 +++
 .../etlserver/phosphonetx/dto/Peptide.java    |  12 ++
 9 files changed, 428 insertions(+), 110 deletions(-)
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbstractSampleHandler.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ModificationFraction.java
 create mode 100644 rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ModificationFractionHandler.java

diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbstractHandler.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbstractHandler.java
index 8b342e98995..040907ec50e 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbstractHandler.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbstractHandler.java
@@ -16,11 +16,9 @@
 
 package ch.systemsx.cisd.openbis.etlserver.phosphonetx;
 
-import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Experiment;
-import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Sample;
 
 /**
- * 
+ * Abstract super class of classes using {@link IProtDAO}.
  *
  * @author Franz-Josef Elmer
  */
@@ -32,17 +30,5 @@ abstract class AbstractHandler
     {
         this.dao = dao;
     }
-    
-    protected Sample getOrCreateSample(Experiment experiment, String samplePermID)
-    {
-        Sample sample = dao.tryToGetSampleByPermID(samplePermID);
-        if (sample == null)
-        {
-            sample = new Sample();
-            sample.setPermID(samplePermID);
-            sample.setId(dao.createSample(experiment.getId(), samplePermID));
-        }
-        return sample;
-    }
 
 }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbstractSampleHandler.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbstractSampleHandler.java
new file mode 100644
index 00000000000..9a771c3a5e1
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbstractSampleHandler.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2011 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.etlserver.phosphonetx;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import ch.rinn.restrictions.Private;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Experiment;
+import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ListSamplesByPropertyCriteria;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.CommonConstants;
+
+/**
+ * Abstract super class of classes getting or creating {@link Sample} instances.
+ *
+ * @author Franz-Josef Elmer
+ */
+abstract class AbstractSampleHandler extends AbstractHandler
+{
+    @Private
+    static final String MZXML_FILENAME = "MZXML_FILENAME";
+
+    protected static final class SampleOrError
+    {
+        Sample sample;
+
+        String error;
+    }
+
+    protected final IEncapsulatedOpenBISService openbisService;
+
+    protected final ExperimentIdentifier experimentIdentifier;
+
+    private final SpaceIdentifier space;
+
+    private final Experiment experiment;
+
+    private final Map<String, SampleOrError> samplesOrErrors = new HashMap<String, SampleOrError>();
+
+    AbstractSampleHandler(IEncapsulatedOpenBISService openbisService, IProtDAO dao,
+            ExperimentIdentifier experimentIdentifier, Experiment experiment)
+    {
+        super(dao);
+        this.openbisService = openbisService;
+        this.experimentIdentifier = experimentIdentifier;
+        this.experiment = experiment;
+        String databaseInstanceCode = experimentIdentifier.getDatabaseInstanceCode();
+        space = new SpaceIdentifier(databaseInstanceCode, CommonConstants.MS_DATA_SPACE);
+    }
+    
+    protected SampleOrError getOrCreateSampleOrError(String sampleName)
+    {
+        SampleOrError sampleOrError = samplesOrErrors.get(sampleName);
+        if (sampleOrError == null)
+        {
+            // first we look for a sample in space MS_DATA
+            SampleIdentifier sampleIdentifier = new SampleIdentifier(space, sampleName);
+            ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample =
+                    openbisService.tryGetSampleWithExperiment(sampleIdentifier);
+            sampleOrError = new SampleOrError();
+            if (sample != null)
+            {
+                sampleOrError.sample = getOrCreateSample(sample.getPermId());
+            } else
+            {
+                // second we look for a sample in same space as search experiment with
+                // a property specified by 'sampleName'
+                String spaceCode = experimentIdentifier.getSpaceCode();
+                List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample> list =
+                        openbisService.listSamplesByCriteria(new ListSamplesByPropertyCriteria(
+                                MZXML_FILENAME, sampleName, spaceCode, null));
+                if (list == null || list.size() == 0)
+                {
+                    sampleOrError.error = "an unidentified sample: " + sampleName;
+                } else if (list.size() > 1)
+                {
+                    sampleOrError.error =
+                            "a not uniquely specified sample (" + list.size()
+                                    + " samples are found): " + sampleName;
+                } else
+                {
+                    sample = list.get(0);
+                    sampleOrError.sample = getOrCreateSample(sample.getPermId());
+                }
+            }
+            if (sample != null)
+            {
+                handleSample(sampleName, sample);
+            }
+            samplesOrErrors.put(sampleName, sampleOrError);
+        }
+        return sampleOrError;
+    }
+
+    private Sample getOrCreateSample(String samplePermID)
+    {
+        Sample sample = dao.tryToGetSampleByPermID(samplePermID);
+        if (sample == null)
+        {
+            sample = new Sample();
+            sample.setPermID(samplePermID);
+            sample.setId(dao.createSample(experiment.getId(), samplePermID));
+        }
+        return sample;
+    }
+    
+    protected abstract void handleSample(String parameterName,
+            ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample);
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandler.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandler.java
index 4235d564efc..754120f59a0 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandler.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/AbundanceHandler.java
@@ -16,11 +16,6 @@
 
 package ch.systemsx.cisd.openbis.etlserver.phosphonetx;
 
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import ch.rinn.restrictions.Private;
 import ch.systemsx.cisd.common.exceptions.UserFailureException;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
 import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Experiment;
@@ -28,51 +23,23 @@ import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Parameter;
 import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.NewSample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
-import ch.systemsx.cisd.openbis.generic.shared.dto.ListSamplesByPropertyCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SampleIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.SpaceIdentifier;
-import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.basic.CommonConstants;
 
 /**
  * Handler of {@link Parameter} objects of type 'abundance'.
  * 
  * @author Franz-Josef Elmer
  */
-class AbundanceHandler extends AbstractHandler
+class AbundanceHandler extends AbstractSampleHandler
 {
-    @Private
-    static final String MZXML_FILENAME = "MZXML_FILENAME";
-
-    private static final class SampleOrError
-    {
-        Sample sample;
-
-        String error;
-    }
-
-    private final IEncapsulatedOpenBISService openbisService;
-
-    private final ExperimentIdentifier experimentIdentifier;
-
-    private final SpaceIdentifier msData;
-
-    private final Experiment experiment;
-
-    private final Map<String, SampleOrError> samplesOrErrors = new HashMap<String, SampleOrError>();
-
     private final SampleType sampleType;
 
     AbundanceHandler(IEncapsulatedOpenBISService openbisService, IProtDAO dao,
             ExperimentIdentifier experimentIdentifier, Experiment experiment)
     {
-        super(dao);
-        this.openbisService = openbisService;
-        this.experimentIdentifier = experimentIdentifier;
-        this.experiment = experiment;
-        msData =
-                new SpaceIdentifier(experimentIdentifier.getDatabaseInstanceCode(),
-                        CommonConstants.MS_DATA_SPACE);
+        super(openbisService, dao, experimentIdentifier, experiment);
         sampleType = new SampleType();
         sampleType.setCode(Constants.SEARCH_SAMPLE_TYPE);
     }
@@ -91,59 +58,9 @@ class AbundanceHandler extends AbstractHandler
         }
     }
 
-    @SuppressWarnings("deprecation")
     private Sample getOrCreateSample(String parameterName, String proteinName)
     {
-        SampleOrError sampleOrError = samplesOrErrors.get(parameterName);
-        if (sampleOrError == null)
-        {
-            // first we look for a sample in space MS_DATA
-            SampleIdentifier sampleIdentifier = new SampleIdentifier(msData, parameterName);
-            ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample =
-                    openbisService.tryGetSampleWithExperiment(sampleIdentifier);
-            sampleOrError = new SampleOrError();
-            if (sample != null)
-            {
-                sampleOrError.sample = getOrCreateSample(experiment, sample.getPermId());
-            } else
-            {
-                // second we look for a sample in same space as search experiment with
-                // a property specified by 'parameterName'
-                String spaceCode = experimentIdentifier.getSpaceCode();
-                List<ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample> list =
-                        openbisService.listSamplesByCriteria(new ListSamplesByPropertyCriteria(
-                                MZXML_FILENAME, parameterName, spaceCode, null));
-                if (list == null || list.size() == 0)
-                {
-                    sampleOrError.error = "an unidentified sample: " + parameterName;
-                } else if (list.size() > 1)
-                {
-                    sampleOrError.error =
-                            "a not uniquely specified sample (" + list.size()
-                                    + " samples are found): " + parameterName;
-                } else
-                {
-                    sample = list.get(0);
-                    sampleOrError.sample = getOrCreateSample(experiment, sample.getPermId());
-                }
-            }
-            if (sample != null)
-            {
-                NewSample searchSample = new NewSample();
-                searchSample.setSampleType(sampleType);
-                SpaceIdentifier spaceIdentifier =
-                        new SpaceIdentifier(experimentIdentifier.getDatabaseInstanceCode(),
-                                experimentIdentifier.getSpaceCode());
-                SampleIdentifier identifier =
-                        new SampleIdentifier(spaceIdentifier, parameterName + "_"
-                                + experimentIdentifier.getExperimentCode());
-                searchSample.setIdentifier(identifier.toString());
-                searchSample.setExperimentIdentifier(experimentIdentifier.toString());
-                searchSample.setParentIdentifier(sample.getIdentifier());
-                openbisService.registerSample(searchSample, null);
-            }
-            samplesOrErrors.put(parameterName, sampleOrError);
-        }
+        SampleOrError sampleOrError = getOrCreateSampleOrError(parameterName);
         if (sampleOrError.error != null)
         {
             throw new UserFailureException("Protein '" + proteinName
@@ -151,4 +68,23 @@ class AbundanceHandler extends AbstractHandler
         }
         return sampleOrError.sample;
     }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    protected void handleSample(String parameterName,
+            ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample)
+    {
+        NewSample searchSample = new NewSample();
+        searchSample.setSampleType(sampleType);
+        SpaceIdentifier spaceIdentifier =
+                new SpaceIdentifier(experimentIdentifier.getDatabaseInstanceCode(),
+                        experimentIdentifier.getSpaceCode());
+        SampleIdentifier identifier =
+                new SampleIdentifier(spaceIdentifier, parameterName + "_"
+                        + experimentIdentifier.getExperimentCode());
+        searchSample.setIdentifier(identifier.toString());
+        searchSample.setExperimentIdentifier(experimentIdentifier.toString());
+        searchSample.setParentIdentifier(sample.getIdentifier());
+        openbisService.registerSample(searchSample, null);
+    }
 }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/IProtDAO.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/IProtDAO.java
index 058bc2417a1..25acfc4a438 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/IProtDAO.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/IProtDAO.java
@@ -73,8 +73,8 @@ public interface IProtDAO extends BaseQuery
     @Select("insert into modified_peptides (pept_id, nterm_mass, cterm_mass) values (?{1}, ?{2}, ?{3}) returning id")
     public long createModifiedPeptide(long peptideID, double nTermMass, double cTermMass);
 
-    @Update("insert into modifications (mope_id, pos, mass) values (?{1}, ?{2}, ?{3})")
-    public void createModification(long modPeptideID, int position, double mass);
+    @Select("insert into modifications (mope_id, pos, mass) values (?{1}, ?{2}, ?{3}) returning id")
+    public long createModification(long modPeptideID, int position, double mass);
 
     @Select("select * from protein_references where accession_number = ?{1}")
     public ProteinReference tryToGetProteinReference(String accessionNumber);
@@ -99,4 +99,7 @@ public interface IProtDAO extends BaseQuery
     @Update("insert into abundances (prot_id, samp_id, value) values (?{1}, ?{2}, ?{3})")
     public void createAbundance(long proteinID, long sampleID, double value);
 
+    @Update("insert into modification_fractions (modi_id, samp_id, fraction) values (?{1}, ?{2}, ?{3})")
+    public void createModificationFraction(long modID, long sampleID, double fraction);
+
 }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ModificationFraction.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ModificationFraction.java
new file mode 100644
index 00000000000..b640ea27206
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ModificationFraction.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011 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.etlserver.phosphonetx;
+
+import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.AminoAcidMass;
+
+/**
+ * Data class keeping data extracted from a peptide <parameter> element of type 'modification'.
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+final class ModificationFraction
+{
+    private final String sample;
+    private final double fraction;
+    private final AminoAcidMass aminoAcidMass;
+    
+    ModificationFraction(String sample, String value)
+    {
+        this.sample = sample;
+        String[] parts = value.split(":");
+        if (parts.length != 3)
+        {
+            throw exception(value, "Three parts separated by ':' expected.");
+        }
+        aminoAcidMass = new AminoAcidMass();
+        try
+        {
+            aminoAcidMass.setPosition(Integer.parseInt(parts[0]));
+        } catch (NumberFormatException ex)
+        {
+            throw exception(value, "Position part isn't an integer number: " + parts[0]);
+        }
+        try
+        {
+            aminoAcidMass.setMass(Double.parseDouble(parts[1]));
+        } catch (NumberFormatException ex)
+        {
+            throw exception(value, "Mass part isn't a floating-point number: " + parts[1]);
+        }
+        try
+        {
+            fraction = Double.parseDouble(parts[2]);
+        } catch (NumberFormatException ex)
+        {
+            throw exception(value, "Fraction part isn't a floating-point number: " + parts[2]);
+        }
+    }
+    
+    private IllegalArgumentException exception(String value, String message)
+    {
+        return new IllegalArgumentException("Peptide parameter value [" + value
+                + "] for sample '" + sample + "' is invalid: " + message);
+    }
+    
+    public String getSample()
+    {
+        return sample;
+    }
+    
+    public AminoAcidMass getAminoAcidMass()
+    {
+        return aminoAcidMass;
+    }
+    
+    public double getFraction()
+    {
+        return fraction;
+    }
+}
\ No newline at end of file
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ModificationFractionHandler.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ModificationFractionHandler.java
new file mode 100644
index 00000000000..961f7bbac4e
--- /dev/null
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ModificationFractionHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011 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.etlserver.phosphonetx;
+
+import java.util.List;
+
+import ch.systemsx.cisd.common.exceptions.UserFailureException;
+import ch.systemsx.cisd.openbis.dss.generic.shared.IEncapsulatedOpenBISService;
+import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Experiment;
+import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Sample;
+import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
+
+/**
+ * Handler of modification fractions.
+ *
+ * @author Franz-Josef Elmer
+ */
+class ModificationFractionHandler extends AbstractSampleHandler
+{
+    public ModificationFractionHandler(IEncapsulatedOpenBISService openbisService, IProtDAO dao,
+            ExperimentIdentifier experimentIdentifier, Experiment experiment)
+    {
+        super(openbisService, dao, experimentIdentifier, experiment);
+    }
+
+    @Override
+    protected void handleSample(String parameterName,
+            ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample sample)
+    {
+        // Do nothing
+    }
+    
+    public void addModificationFractions(String peptideSequence, long modID,
+            List<ModificationFraction> modificationFractions)
+    {
+        for (ModificationFraction modificationFraction : modificationFractions)
+        {
+            Sample sample = getOrCreateSample(modificationFraction.getSample(), peptideSequence);
+            double fraction = modificationFraction.getFraction();
+            dao.createModificationFraction(modID, sample.getId(), fraction);
+        }
+    }
+
+    private Sample getOrCreateSample(String sampleName, String peptideSequence)
+    {
+        SampleOrError sampleOrError = getOrCreateSampleOrError(sampleName);
+        if (sampleOrError.error != null)
+        {
+            throw new UserFailureException("Protein '" + peptideSequence
+                    + "' has an abundance value for " + sampleOrError.error);
+        }
+        return sampleOrError.sample;
+    }
+
+}
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ResultDataSetUploader.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ResultDataSetUploader.java
index 4e8344d7b90..f6ad0840c1c 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ResultDataSetUploader.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/ResultDataSetUploader.java
@@ -18,8 +18,12 @@ package ch.systemsx.cisd.openbis.etlserver.phosphonetx;
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 
 import net.lemnik.eodsql.QueryTool;
@@ -45,6 +49,7 @@ import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.ProteinProphetDetails;
 import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.ProteinReference;
 import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.ProteinSummary;
 import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.ProteinSummaryDataFilter;
+import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Sample;
 import ch.systemsx.cisd.openbis.etlserver.phosphonetx.dto.Sequence;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.ProbabilityToFDRCalculator;
@@ -59,6 +64,8 @@ class ResultDataSetUploader extends AbstractHandler
     private static final double MAX_FALSE_DISCOVERY_RATE = 0.1;
 
     static final String PARAMETER_TYPE_ABUNDANCE = "abundance";
+    
+    static final String PARAMETER_TYPE_MODIFICATION = "modification";
 
     private final Connection connection;
 
@@ -198,6 +205,9 @@ class ResultDataSetUploader extends AbstractHandler
         Long databaseID = dataSet.getDatabaseID();
         AbundanceHandler abundanceHandler =
                 new AbundanceHandler(openbisService, dao, experimentIdentifier, experiment);
+        ModificationFractionHandler modificationFractionHandler =
+                new ModificationFractionHandler(openbisService, dao, experimentIdentifier,
+                        experiment);
         ProbabilityToFDRCalculator calculator = createProbabilityToFDRMapping(dataSetID, summary);
         List<ProteinGroup> proteinGroups = summary.getProteinGroups();
         for (ProteinGroup proteinGroup : proteinGroups)
@@ -211,7 +221,8 @@ class ResultDataSetUploader extends AbstractHandler
                 {
                     if (calculator.calculateFDR(protein.getProbability()) <= MAX_FALSE_DISCOVERY_RATE)
                     {
-                        addProtein(protein, dataSetID, databaseID, abundanceHandler);
+                        addProtein(protein, dataSetID, databaseID, abundanceHandler,
+                                modificationFractionHandler);
                     }
                 } catch (Exception e)
                 {
@@ -236,7 +247,8 @@ class ResultDataSetUploader extends AbstractHandler
     }
 
     private void addProtein(Protein protein, long dataSetID, Long databaseID,
-            AbundanceHandler abundanceHandler)
+            AbundanceHandler abundanceHandler,
+            ModificationFractionHandler modificationFractionHandler)
     {
         long proteinID = dao.createProtein(dataSetID, protein.getProbability());
         for (Parameter parameter : protein.getParameters())
@@ -252,7 +264,7 @@ class ResultDataSetUploader extends AbstractHandler
         {
             try
             {
-                addPeptide(proteinID, peptide);
+                addPeptide(proteinID, peptide, modificationFractionHandler);
                 peptideSequences.add(peptide.getSequence());
             } catch (Exception e)
             {
@@ -266,7 +278,8 @@ class ResultDataSetUploader extends AbstractHandler
         }
     }
 
-    private void addPeptide(long proteinID, Peptide peptide)
+    private void addPeptide(long proteinID, Peptide peptide,
+            ModificationFractionHandler modificationFractionHandler)
     {
         String peptideSequence = peptide.getSequence();
         int charge = peptide.getCharge();
@@ -282,6 +295,54 @@ class ResultDataSetUploader extends AbstractHandler
                 logException(e, "modification", modification.toString());
             }
         }
+        List<ModificationFraction> modificationFractions = extractModificationFractions(peptide);
+        if (modificationFractions.isEmpty())
+        {
+            return;
+        }
+        long modPeptideID = dao.createModifiedPeptide(peptideID, 0, 0);
+        Map<AminoAcidMass, List<ModificationFraction>> map =
+                groupByPositionAndMass(modificationFractions);
+        Set<Entry<AminoAcidMass, List<ModificationFraction>>> entrySet = map.entrySet();
+        for (Entry<AminoAcidMass, List<ModificationFraction>> entry : entrySet)
+        {
+            AminoAcidMass positionAndMass = entry.getKey();
+            long modID = createModification(modPeptideID, positionAndMass);
+            List<ModificationFraction> list = entry.getValue();
+            modificationFractionHandler.addModificationFractions(peptideSequence, modID, list);
+        }
+    }
+
+    private Map<AminoAcidMass, List<ModificationFraction>> groupByPositionAndMass(
+            List<ModificationFraction> modificationFractions)
+    {
+        Map<AminoAcidMass, List<ModificationFraction>> result =
+                new HashMap<AminoAcidMass, List<ModificationFraction>>();
+        for (ModificationFraction modificationFraction : modificationFractions)
+        {
+            AminoAcidMass positionAndMass = modificationFraction.getAminoAcidMass();
+            List<ModificationFraction> list = result.get(positionAndMass);
+            if (list == null)
+            {
+                list = new ArrayList<ModificationFraction>();
+                result.put(positionAndMass, list);
+            }
+            list.add(modificationFraction);
+        }
+        return result;
+    }
+    
+    private List<ModificationFraction> extractModificationFractions(Peptide peptide)
+    {
+        List<ModificationFraction> result = new ArrayList<ModificationFraction>();
+        for (Parameter parameter : peptide.getParameters())
+        {
+            if (PARAMETER_TYPE_MODIFICATION.equals(parameter.getType()))
+            {
+                result.add(new ModificationFraction(parameter.getName(), parameter.getValue()));
+            }
+        }
+        return result;
     }
 
     private void addPeptideModification(long peptideID, PeptideModification modification)
@@ -292,12 +353,16 @@ class ResultDataSetUploader extends AbstractHandler
         List<AminoAcidMass> aminoAcidMasses = modification.getAminoAcidMasses();
         for (AminoAcidMass aminoAcidMass : aminoAcidMasses)
         {
-            double mass = aminoAcidMass.getMass();
-            int position = aminoAcidMass.getPosition();
-            dao.createModification(modPeptideID, position, mass);
+            createModification(modPeptideID, aminoAcidMass);
         }
     }
 
+    private long createModification(long modPeptideID, AminoAcidMass aminoAcidMass)
+    {
+        return dao.createModification(modPeptideID, aminoAcidMass.getPosition(),
+                aminoAcidMass.getMass());
+    }
+    
     private void createIdentifiedProtein(long proteinID, Set<String> peptideSequences,
             Long databaseID, ProteinAnnotation annotation, boolean primary)
     {
@@ -380,4 +445,16 @@ class ResultDataSetUploader extends AbstractHandler
         }
         throw new UserFailureException("Missing Protein Prophet details.");
     }
+
+    protected Sample getOrCreateSample(Experiment experiment, String samplePermID)
+    {
+        Sample sample = dao.tryToGetSampleByPermID(samplePermID);
+        if (sample == null)
+        {
+            sample = new Sample();
+            sample.setPermID(samplePermID);
+            sample.setId(dao.createSample(experiment.getId(), samplePermID));
+        }
+        return sample;
+    }
 }
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/dto/AminoAcidMass.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/dto/AminoAcidMass.java
index 91801aa5624..2e948ec5330 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/dto/AminoAcidMass.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/dto/AminoAcidMass.java
@@ -48,6 +48,27 @@ public class AminoAcidMass
         this.mass = mass;
     }
     
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == this)
+        {
+            return true;
+        }
+        if (obj instanceof AminoAcidMass == false)
+        {
+            return false;
+        }
+        AminoAcidMass that = (AminoAcidMass) obj;
+        return this.position == that.position && this.mass == that.mass;
+    }
+    
+    @Override
+    public int hashCode()
+    {
+        return (int) (37 * position + mass);
+    }
+    
     @Override
     public String toString()
     {
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/dto/Peptide.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/dto/Peptide.java
index 2d7da97a5a7..26020f39c3d 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/dto/Peptide.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/etlserver/phosphonetx/dto/Peptide.java
@@ -38,6 +38,7 @@ public class Peptide
     private int charge;
     private double initialProbability;
     private double weight;
+    private List<Parameter> parameters = new ArrayList<Parameter>();
     private List<PeptideModification> modifications = new ArrayList<PeptideModification>();
 
     @XmlAttribute(name = "peptide_sequence", required = true)
@@ -95,6 +96,17 @@ public class Peptide
         this.modifications = modifications;
     }
 
+    @XmlElement(name = "parameter", namespace = Constants.NAMESPACE)
+    public final List<Parameter> getParameters()
+    {
+        return parameters;
+    }
+
+    public final void setParameters(List<Parameter> parameters)
+    {
+        this.parameters = parameters;
+    }
+
     @Override
     public String toString()
     {
-- 
GitLab