diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/IProteinWithAbundancesTable.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/IProteinWithAbundancesTable.java
index cc91c22fc726d813a1745b1e63ae2788582f17dd..a4559040d722dea16bc99d9bcdf80b5670ef2683 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/IProteinWithAbundancesTable.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/IProteinWithAbundancesTable.java
@@ -22,12 +22,16 @@ import java.util.Set;
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinWithAbundances;
 
 /**
- * 
+ * Business object for loading proteins together with their abundances.
  *
  * @author Franz-Josef Elmer
  */
 public interface IProteinWithAbundancesTable
 {
+    /**
+     * Loads proteins of all data sets registered for the specified experiment. All proteins
+     * are filtered out if their false discovery rate is larger then the specifie one.
+     */
     public void load(String experimentPermID, double falseDiscoveryRate);
     
     public Collection<ProteinWithAbundances> getProteinsWithAbundances();
diff --git a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinWithAbundancesTable.java b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinWithAbundancesTable.java
index 2507732e0d6027022225ea24b85a638d314162d0..0788af1d9bad71f8bc2d517f2886e1a050c4c080 100644
--- a/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinWithAbundancesTable.java
+++ b/rtd_phosphonetx/source/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinWithAbundancesTable.java
@@ -30,7 +30,7 @@ import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWi
 import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinWithAbundances;
 
 /**
- * 
+ * Implementation based of {@link IDAOFactory} and {@link IPhosphoNetXDAOFactory}.
  *
  * @author Franz-Josef Elmer
  */
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 be627d6a6c1393d1ad6141034ba9bfbb1de1beb9..b6701cddc760d2133b397c8469d5499673b089e5 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,7 +16,7 @@
 
 package ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto;
 
-import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -29,7 +29,7 @@ public class ProteinWithAbundances extends ProteinReference
 {
     private static final double[] EMPTY_ARRAY = new double[0];
     
-    private final Map<Long, double[]> abundances = new HashMap<Long, double[]>();
+    private final Map<Long, double[]> abundances = new LinkedHashMap<Long, double[]>();
     
     public void addAbundanceFor(long sampleID, double abundance)
     {
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
new file mode 100644
index 0000000000000000000000000000000000000000..9d7b516b549d5512da47db7217a562ff102d3f0c
--- /dev/null
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/AbundanceManagerTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2009 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 java.util.Collection;
+import java.util.Iterator;
+
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinWithAbundances;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class AbundanceManagerTest extends AssertJUnit
+{
+
+    @Test
+    public void testNoProteinReferenceHandled()
+    {
+        AbundanceManager abundanceManager = new AbundanceManager();
+        assertEquals(0, abundanceManager.getSampleIDs().size());
+        assertEquals(0, abundanceManager.getProteinsWithAbundances().size());
+    }
+    
+    @Test
+    public void testHandleTwoProteinReferencesButOnlyOneHasAnAbundance()
+    {
+        AbundanceManager abundanceManager = new AbundanceManager();
+        ProteinReferenceWithProbability protein1 = new ProteinReferenceWithProbability();
+        protein1.setId(1);
+        protein1.setAccessionNumber("abc1");
+        protein1.setDescription("abc one");
+        protein1.setSampleID(101L);
+        protein1.setAbundance(1.5);
+        abundanceManager.handle(protein1);
+        ProteinReferenceWithProbability protein2 = new ProteinReferenceWithProbability();
+        protein2.setId(2);
+        protein2.setAccessionNumber("abc2");
+        protein2.setDescription("abc two");
+        abundanceManager.handle(protein2);
+        
+        assertEquals(1, abundanceManager.getSampleIDs().size());
+        Collection<ProteinWithAbundances> proteinsWithAbundances = abundanceManager.getProteinsWithAbundances();
+        assertEquals(2, proteinsWithAbundances.size());
+        Iterator<ProteinWithAbundances> iterator = proteinsWithAbundances.iterator();
+        ProteinWithAbundances p1 = iterator.next();
+        assertEquals(1, p1.getId());
+        assertEquals("abc one", p1.getDescription());
+        assertEquals("abc1", p1.getAccessionNumber());
+        assertEquals(1, p1.getSampleIDs().size());
+        assertEquals(101, p1.getSampleIDs().iterator().next().longValue());
+        assertEquals(0, p1.getAbundancesForSample(12345678).length);
+        assertEquals(1, p1.getAbundancesForSample(101).length);
+        assertEquals(1.5, p1.getAbundancesForSample(101)[0]);
+        ProteinWithAbundances p2 = iterator.next();
+        assertEquals(2, p2.getId());
+        assertEquals("abc two", p2.getDescription());
+        assertEquals("abc2", p2.getAccessionNumber());
+        assertEquals(0, p2.getSampleIDs().size());
+    }
+    
+    @Test
+    public void testHandleProteinReferencesWithManyAbundancesForTwoSamples()
+    {
+        AbundanceManager abundanceManager = new AbundanceManager();
+        abundanceManager.handle(createProteinReference(101, 1.5));
+        abundanceManager.handle(createProteinReference(101, 2.25));
+        abundanceManager.handle(createProteinReference(102, 42));
+        abundanceManager.handle(createProteinReference(102, 4.75));
+        abundanceManager.handle(createProteinReference(102, 7.5));
+        
+        assertEquals(2, abundanceManager.getSampleIDs().size());
+        Collection<ProteinWithAbundances> proteinsWithAbundances = abundanceManager.getProteinsWithAbundances();
+        assertEquals(1, proteinsWithAbundances.size());
+        ProteinWithAbundances protein = proteinsWithAbundances.iterator().next();
+        assertEquals(1, protein.getId());
+        assertEquals("abc one", protein.getDescription());
+        assertEquals("abc1", protein.getAccessionNumber());
+        assertEquals(2, protein.getSampleIDs().size());
+        Iterator<Long> iterator = protein.getSampleIDs().iterator();
+        assertEquals(101, iterator.next().longValue());
+        assertEquals(102, iterator.next().longValue());
+        assertEquals(2, protein.getAbundancesForSample(101).length);
+        assertEquals(1.5, protein.getAbundancesForSample(101)[0]);
+        assertEquals(2.25, protein.getAbundancesForSample(101)[1]);
+        assertEquals(3, protein.getAbundancesForSample(102).length);
+        assertEquals(42.0, protein.getAbundancesForSample(102)[0]);
+        assertEquals(4.75, protein.getAbundancesForSample(102)[1]);
+        assertEquals(7.5, protein.getAbundancesForSample(102)[2]);
+    }
+
+    private ProteinReferenceWithProbability createProteinReference(long sampleID, double abundance)
+    {
+        ProteinReferenceWithProbability protein1 = new ProteinReferenceWithProbability();
+        protein1.setId(1);
+        protein1.setAccessionNumber("abc1");
+        protein1.setDescription("abc one");
+        protein1.setSampleID(sampleID);
+        protein1.setAbundance(abundance);
+        return protein1;
+    }
+}
diff --git a/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinWithAbundancesTableTest.java b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinWithAbundancesTableTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..85e6cf920f8ec3dc1df65501dea9d0e74c5daa38
--- /dev/null
+++ b/rtd_phosphonetx/sourceTest/java/ch/systemsx/cisd/openbis/plugin/phosphonetx/server/business/ProteinWithAbundancesTableTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2009 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 java.util.Collection;
+import java.util.Set;
+
+import org.jmock.Expectations;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.openbis.generic.shared.AbstractServerTestCase;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.server.MockDataSet;
+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.ProbabilityFDRMapping;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinReferenceWithProbability;
+import ch.systemsx.cisd.openbis.plugin.phosphonetx.shared.dto.ProteinWithAbundances;
+
+/**
+ * 
+ *
+ * @author Franz-Josef Elmer
+ */
+public class ProteinWithAbundancesTableTest extends AbstractServerTestCase
+{
+    private static final Double ABUNDANCE = new Double(47.11);
+    private static final long PROTEIN_ID = 41L;
+    private static final long SAMPLE_ID = 4711L;
+    private static final long DATA_SET_ID = 42L;
+    private static final String EXPERIMENT_ID = "abc-234";
+    private static final double FALSE_DISCOVERY_RATE = 0.25;
+    private static final String ACCESSION_NUMBER = "ABC123";
+    
+    private IPhosphoNetXDAOFactory specificDAOFactory;
+    private IProteinQueryDAO proteinDAO;
+    private ProteinWithAbundancesTable table;
+    
+    @Override
+    @BeforeMethod
+    public void setUp()
+    {
+        super.setUp();
+        specificDAOFactory = context.mock(IPhosphoNetXDAOFactory.class);
+        proteinDAO = context.mock(IProteinQueryDAO.class);
+        context.checking(new Expectations()
+            {
+                {
+                    allowing(specificDAOFactory).getProteinQueryDAO();
+                    will(returnValue(proteinDAO));
+                }
+            });
+        table = new ProteinWithAbundancesTable(daoFactory, specificDAOFactory, SESSION);
+    }
+    
+    @Test
+    public void testLoadLeadingToAnEmptyTable()
+    {
+        final MockDataSet<ProteinReferenceWithProbability> dataSet =
+                new MockDataSet<ProteinReferenceWithProbability>();
+        context.checking(new Expectations()
+            {
+                {
+                    one(proteinDAO).listProteinsByExperiment(EXPERIMENT_ID);
+                    will(returnValue(dataSet));
+                }
+            });
+        
+        table.load(EXPERIMENT_ID, FALSE_DISCOVERY_RATE);
+        
+        assertEquals(0, table.getSampleIDs().size());
+        assertEquals(0, table.getProteinsWithAbundances().size());
+        
+        assertEquals(true, dataSet.hasCloseBeenInvoked());
+        context.assertIsSatisfied();
+    }
+
+    @Test
+    public void testLoad()
+    {
+        final MockDataSet<ProteinReferenceWithProbability> dataSet =
+            new MockDataSet<ProteinReferenceWithProbability>();
+        ProteinReferenceWithProbability proteinReference = new ProteinReferenceWithProbability();
+        proteinReference.setDataSetID(DATA_SET_ID);
+        proteinReference.setSampleID(SAMPLE_ID);
+        proteinReference.setAccessionNumber(ACCESSION_NUMBER);
+        proteinReference.setId(PROTEIN_ID);
+        proteinReference.setAbundance(ABUNDANCE);
+        dataSet.add(proteinReference);
+        proteinReference = new ProteinReferenceWithProbability();
+        proteinReference.setProbability(1);
+        proteinReference.setDataSetID(DATA_SET_ID);
+        dataSet.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);
+        context.checking(new Expectations()
+        {
+            {
+                one(proteinDAO).listProteinsByExperiment(EXPERIMENT_ID);
+                will(returnValue(dataSet));
+                
+                one(proteinDAO).getProbabilityFDRMapping(DATA_SET_ID);
+                will(returnValue(mappings));
+            }
+        });
+        
+        table.load(EXPERIMENT_ID, FALSE_DISCOVERY_RATE);
+        
+        Set<Long> sampleIDs = table.getSampleIDs();
+        assertEquals(1, sampleIDs.size());
+        Long sampleID = sampleIDs.iterator().next();
+        assertEquals(SAMPLE_ID, sampleID.longValue());
+        Collection<ProteinWithAbundances> proteins = table.getProteinsWithAbundances();
+        assertEquals(1, proteins.size());
+        ProteinWithAbundances protein = proteins.iterator().next();
+        assertEquals(PROTEIN_ID, protein.getId());
+        assertEquals(ACCESSION_NUMBER, protein.getAccessionNumber());
+        assertEquals(sampleIDs, protein.getSampleIDs());
+        double[] abundances = protein.getAbundancesForSample(sampleID);
+        assertEquals(1, abundances.length);
+        assertEquals(ABUNDANCE, abundances[0]);
+        
+        assertEquals(true, dataSet.hasCloseBeenInvoked());
+        assertEquals(true, mappings.hasCloseBeenInvoked());
+        context.assertIsSatisfied();
+    }
+    
+}