diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property/PropertyGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property/PropertyGrid.java
index 6e70185b237409b7c9e584abe44bc2d971727d10..a49829e117ca24e5fc2457840d3441c83fb6edb8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property/PropertyGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/property/PropertyGrid.java
@@ -18,9 +18,10 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.proper
 
 import java.util.Date;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
+import java.util.Map.Entry;
 
+import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.ui.Grid;
 import com.google.gwt.user.client.ui.Widget;
 
@@ -54,7 +55,7 @@ public final class PropertyGrid extends Grid
     private final Map<Class<?>, IPropertyValueRenderer<?>> propertyValueRenderers =
             new HashMap<Class<?>, IPropertyValueRenderer<?>>();
 
-    private Map<String, ?> properties;
+    private Map<String, Object> properties;
 
     private final IViewContext<?> viewContext;
 
@@ -162,13 +163,14 @@ public final class PropertyGrid extends Grid
     /**
      * Sets the properties that are going to be displayed here.
      */
-    public final <T> void setProperties(final Map<String, ? super T> properties)
+    public final void setProperties(final Map<String, Object> properties)
     {
         this.properties = properties;
-        fillTable();
+        assert properties != null : "Unspecified properties.";
+        addPropertiesToTable(properties, 0);
     }
 
-    public Map<String, ?> getProperties()
+    public Map<String, Object> getProperties()
     {
         return properties;
     }
@@ -180,17 +182,27 @@ public final class PropertyGrid extends Grid
         return propertyValueRenderer.getAsWidget(value);
     }
 
-    private final void fillTable()
+    public void addAdditionalProperties(String title, Map<String, Object> props)
     {
-        assert properties != null : "Unspecified properties.";
-        int row = 0;
-        for (final Iterator<String> iterator = properties.keySet().iterator(); iterator.hasNext(); row++)
+        int row = getRowCount();
+        resizeRows(row + 1 + props.size());
+        setHTML(row, 0, title);
+        Element element = getCellFormatter().getElement(row, 0);
+        element.setAttribute("colspan", "2");
+        element.setAttribute("class", "properties-sub-section");
+        addPropertiesToTable(props, row + 1);
+    }
+
+    private void addPropertiesToTable(Map<String, Object> props, int initRow)
+    {
+        int row = initRow;
+        for (Entry<String, Object> entry : props.entrySet())
         {
-            final String key = iterator.next();
-            final Object value = properties.get(key);
-            final Widget widget = getAsWidget(value);
+            String key = entry.getKey();
+            Object value = entry.getValue();
+            Widget widget = getAsWidget(value);
             setHTML(row, 0, key);
-            setWidget(row, 1, widget);
+            setWidget(row++, 1, widget);
         }
     }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/BaseEntityPropertyRecord.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/BaseEntityPropertyRecord.java
index 2afec55c0499d6619a36041cafaef6b783e3ec28..2e0a4d6ada25389e5013075a1e299e8b7bdb926d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/BaseEntityPropertyRecord.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/BaseEntityPropertyRecord.java
@@ -12,4 +12,6 @@ public class BaseEntityPropertyRecord
     public Long script_id;
 
     public String script_type;
+
+    public Long ordinal;
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/EntityPropertiesEnricher.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/EntityPropertiesEnricher.java
index f204e421bf455067e2a1e2462bb153de8fee7815..0859635bdd40ea72b35178e164b5247371963a1f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/EntityPropertiesEnricher.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/EntityPropertiesEnricher.java
@@ -126,6 +126,7 @@ public final class EntityPropertiesEnricher implements IEntityPropertiesEnricher
             property.setPropertyType(propertyTypes.get(val.prty_id));
             property.setScriptable(val.script_id != null);
             property.setDynamic(ScriptType.DYNAMIC_PROPERTY.name().equals(val.script_type));
+            property.setOrdinal(val.ordinal);
             entity.getProperties().add(property);
         }
 
@@ -163,6 +164,7 @@ public final class EntityPropertiesEnricher implements IEntityPropertiesEnricher
             }
             property.setVocabularyTerm(vocabularyTerm);
             property.setPropertyType(propertyTypes.get(val.prty_id));
+            property.setOrdinal(val.ordinal);
             entity.getProperties().add(property);
         }
 
@@ -189,6 +191,7 @@ public final class EntityPropertiesEnricher implements IEntityPropertiesEnricher
             }
             property.setMaterial(material);
             property.setPropertyType(propertyTypes.get(val.prty_id));
+            property.setOrdinal(val.ordinal);
             entity.getProperties().add(property);
         }
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/VocabularyTermRecord.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/VocabularyTermRecord.java
index 6bab551b747da766d4346e026a8dd1010541cc94..e29d488aff2f6b18a3ce1fd58783d341d6a98820 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/VocabularyTermRecord.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/common/VocabularyTermRecord.java
@@ -13,5 +13,5 @@ public class VocabularyTermRecord extends BaseEntityPropertyRecord
 
     public String label;
 
-    public long ordinal;
+    public long term_ordinal;
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java
index 109ca510c40990f76a64cb4c7b77aa118c8d4ad4..0f56e2d9fd2925fa13761bd0d004b62f1c354892 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/samplelister/ISampleListingQuery.java
@@ -388,7 +388,7 @@ public interface ISampleListingQuery extends TransactionQuery, IPropertyListingQ
      * 
      * @param sampleIds The set of sample ids to get the property values for.
      */
-    @Select(sql = "SELECT sp.samp_id as entity_id, stpt.prty_id, stpt.script_id, sp.value, sc.script_type "
+    @Select(sql = "SELECT sp.samp_id as entity_id, stpt.prty_id, stpt.script_id, stpt.ordinal, sp.value, sc.script_type "
             + "      FROM sample_properties sp"
             + "      JOIN sample_type_property_types stpt ON sp.stpt_id=stpt.id"
             + "      LEFT OUTER JOIN scripts sc ON stpt.script_id = sc.id"
@@ -403,7 +403,8 @@ public interface ISampleListingQuery extends TransactionQuery, IPropertyListingQ
      * 
      * @param sampleIds The set of sample ids to get the property values for.
      */
-    @Select(sql = "SELECT sp.samp_id as entity_id, stpt.prty_id, stpt.script_id, cvte.id, cvte.covo_id, cvte.code, cvte.label, cvte.ordinal, cvte.is_official"
+    @Select(sql = "SELECT sp.samp_id as entity_id, stpt.prty_id, stpt.script_id, stpt.ordinal, "
+            + "           cvte.id, cvte.covo_id, cvte.code, cvte.label, cvte.ordinal as term_ordinal, cvte.is_official"
             + "      FROM sample_properties sp"
             + "      JOIN sample_type_property_types stpt ON sp.stpt_id=stpt.id"
             + "      JOIN controlled_vocabulary_terms cvte ON sp.cvte_id=cvte.id"
@@ -417,7 +418,7 @@ public interface ISampleListingQuery extends TransactionQuery, IPropertyListingQ
      * 
      * @param sampleIds The set of sample ids to get the property values for.
      */
-    @Select(sql = "SELECT sp.samp_id as entity_id, stpt.prty_id, stpt.script_id, m.id, m.code, m.maty_id"
+    @Select(sql = "SELECT sp.samp_id as entity_id, stpt.prty_id, stpt.script_id, stpt.ordinal, m.id, m.code, m.maty_id"
             + "      FROM sample_properties sp"
             + "      JOIN sample_type_property_types stpt ON sp.stpt_id=stpt.id"
             + "      JOIN materials m ON sp.mate_prop_id=m.id "
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/DemoSampleViewer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/DemoSampleViewer.java
index f80b72e3caa424cb5388b3ed00e7d68348f07011..f41f6cc6fbf28f8b2d7a9c40629080ef0057f2c3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/DemoSampleViewer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/demo/client/web/client/application/DemoSampleViewer.java
@@ -64,7 +64,7 @@ public final class DemoSampleViewer extends AbstractViewer<Sample>
 
     private final Widget createUI(final SampleParentWithDerived sampleGeneration)
     {
-        return GenericSampleViewer.createPropertyGrid(sampleId, sampleGeneration, getViewContext());
+        return GenericSampleViewer.createPropertyGrid(getViewContext(), sampleId);
     }
 
     /**
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleViewer.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleViewer.java
index 609c3b69d2105a368fa87f2de623f6d262fa5d59..6b1fb106a28f1f3a7c3c8f2ec8be1fed50399758 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleViewer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/GenericSampleViewer.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Set;
 
 import com.extjs.gxt.ui.client.Style.Scroll;
@@ -52,6 +53,10 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.SectionsPanel;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IDelegatedAction;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.util.IMessageProvider;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.GridRowModels;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.ListSampleDisplayCriteria2;
+import ch.systemsx.cisd.openbis.generic.client.web.client.dto.TypedTableResultSet;
+import ch.systemsx.cisd.openbis.generic.shared.basic.GridRowModel;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IIdAndCodeHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKind;
@@ -59,9 +64,12 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DatabaseModificationKin
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.EntityKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ListSampleCriteria;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleParentWithDerived;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.SampleType;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.TableModelRowWithObject;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.WebAppContext;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.IGenericClientServiceAsync;
 import ch.systemsx.cisd.openbis.plugin.generic.client.web.client.application.PropertiesPanelUtils;
@@ -314,30 +322,69 @@ abstract public class GenericSampleViewer extends AbstractViewerWithVerticalSpli
         final ContentPanel panel = new ContentPanel();
         panel.setScrollMode(Scroll.AUTOY);
         panel.setHeading(getViewContext().getMessage(Dict.SAMPLE_PROPERTIES_HEADING));
-        propertyGrid = createPropertyGrid(sampleId, sampleGeneration, getViewContext());
+        propertyGrid = createPropertyGrid(getViewContext(), sampleId);
+        updateProperties(sampleGeneration);
         panel.add(propertyGrid);
 
         return panel;
     }
 
-    public static PropertyGrid createPropertyGrid(final TechId sampleId,
-            final SampleParentWithDerived sampleGeneration, final IViewContext<?> viewContext)
+    public static PropertyGrid createPropertyGrid(final IViewContext<?> viewContext,
+            final TechId sampleId)
     {
         final IMessageProvider messageProvider = viewContext;
-        final Map<String, Object> properties = createProperties(viewContext, sampleGeneration);
-        final PropertyGrid propertyGrid = new PropertyGrid(viewContext, properties.size());
+        final PropertyGrid propertyGrid = new PropertyGrid(viewContext, 0);
         propertyGrid.registerPropertyValueRenderer(SampleType.class,
                 PropertyValueRenderers.createSampleTypePropertyValueRenderer(messageProvider));
-        propertyGrid.setProperties(properties);
-        propertyGrid.getElement().setId(PROPERTIES_ID_PREFIX + sampleId);
         return propertyGrid;
     }
 
     public final void updateProperties(final SampleParentWithDerived sampleGeneration)
     {
-        final Map<String, Object> properties = createProperties(getViewContext(), sampleGeneration);
-        propertyGrid.resizeRows(properties.size());
+        propertyGrid.resizeRows(0);
+        final Map<String, Object> properties = createProperties(viewContext, sampleGeneration);
         propertyGrid.setProperties(properties);
+        propertyGrid.getElement().setId(PROPERTIES_ID_PREFIX + sampleId);
+        Sample sample = sampleGeneration.getParent();
+        SampleType sampleType = sample.getSampleType();
+        if (sampleType.isShowParentMetadata())
+        {
+            Set<Sample> parents = sample.getParents();
+            if (parents.isEmpty() == false)
+            {
+                ListSampleCriteria listCriteria =
+                        ListSampleCriteria.createForChild(new TechId(sample.getId()));
+                viewContext.getCommonService().listSamples2(
+                        new ListSampleDisplayCriteria2(listCriteria),
+                        new AbstractAsyncCallback<TypedTableResultSet<Sample>>(viewContext)
+                            {
+                                @Override
+                                protected void process(TypedTableResultSet<Sample> result)
+                                {
+                                    GridRowModels<TableModelRowWithObject<Sample>> list =
+                                            result.getResultSet().getList();
+                                    ParentsPropertiesSectionBuilder builder =
+                                            new ParentsPropertiesSectionBuilder();
+                                    for (GridRowModel<TableModelRowWithObject<Sample>> row : list)
+                                    {
+                                        Sample parent = row.getOriginalObject().getObjectOrNull();
+                                        builder.addParent(parent);
+                                    }
+                                    for (Entry<String, List<IEntityProperty>> entry : builder
+                                            .getSections().entrySet())
+                                    {
+                                        String title = entry.getKey();
+                                        List<IEntityProperty> parentProperties = entry.getValue();
+                                        Map<String, Object> props =
+                                                new LinkedHashMap<String, Object>();
+                                        PropertiesPanelUtils.addEntityProperties(viewContext,
+                                                props, parentProperties);
+                                        propertyGrid.addAdditionalProperties(title, props);
+                                    }
+                                }
+                            });
+            }
+        }
     }
 
     /**
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/ParentsPropertiesSectionBuilder.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/ParentsPropertiesSectionBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..b2d8659cacbe92e9dd8ccaa9df511c6fd4478360
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/ParentsPropertiesSectionBuilder.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2012 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.generic.client.web.client.application.sample;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataTypeCode;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
+
+/**
+ * Helper class for building properties sections for the parents of a sample.
+ * 
+ * @author Franz-Josef Elmer
+ */
+class ParentsPropertiesSectionBuilder
+{
+    private static final class Key
+    {
+        private final String code;
+
+        private final DataTypeCode dataType;
+
+        private final String value;
+
+        Key(IEntityProperty property)
+        {
+            code = property.getPropertyType().getCode();
+            dataType = property.getPropertyType().getDataType().getCode();
+            value = property.tryGetAsString();
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (this == obj)
+            {
+                return true;
+            }
+            if (obj instanceof Key == false)
+            {
+                return false;
+            }
+            Key key = (Key) obj;
+            return code.equals(key.code) && dataType.equals(key.dataType)
+                    && value.equals(key.value);
+        }
+
+        @Override
+        public int hashCode()
+        {
+            int hashCode = code.hashCode();
+            hashCode = 37 * hashCode + dataType.hashCode();
+            hashCode = 37 * hashCode + value.hashCode();
+            return hashCode;
+        }
+
+    }
+
+    private final List<Sample> samples = new ArrayList<Sample>();
+
+    void addParent(Sample sample)
+    {
+        samples.add(sample);
+    }
+
+    Map<String, List<IEntityProperty>> getSections()
+    {
+        Map<String, List<IEntityProperty>> sections =
+                new LinkedHashMap<String, List<IEntityProperty>>();
+        Set<Key> commonKeys = new HashSet<ParentsPropertiesSectionBuilder.Key>();
+        if (samples.size() > 1)
+        {
+            Map<Key, List<IEntityProperty>> keys = getCommonPropertiesGroups();
+            List<IEntityProperty> commonProperties = new ArrayList<IEntityProperty>();
+            for (Entry<Key, List<IEntityProperty>> entry : keys.entrySet())
+            {
+                Key key = entry.getKey();
+                List<IEntityProperty> list = entry.getValue();
+                if (list.size() == samples.size())
+                {
+                    commonProperties.add(list.get(0));
+                    commonKeys.add(key);
+                }
+            }
+            if (commonProperties.isEmpty() == false)
+            {
+                sections.put("Properties common by all parents", commonProperties);
+            }
+        }
+        for (Sample sample : samples)
+        {
+            List<IEntityProperty> properties = sample.getProperties();
+            for (Iterator<IEntityProperty> iterator = properties.iterator(); iterator.hasNext();)
+            {
+                if (commonKeys.contains(new Key(iterator.next())))
+                {
+                    iterator.remove();
+                }
+            }
+            if (properties.isEmpty() == false)
+            {
+                sections.put("Properties of " + sample.getIdentifier(), properties);
+            }
+        }
+        return sections;
+    }
+
+    private Map<Key, List<IEntityProperty>> getCommonPropertiesGroups()
+    {
+        Map<Key, List<IEntityProperty>> keys = new LinkedHashMap<Key, List<IEntityProperty>>();
+        for (Sample sample : samples)
+        {
+            List<IEntityProperty> properties = sample.getProperties();
+            for (IEntityProperty property : properties)
+            {
+                Key key = new Key(property);
+                List<IEntityProperty> list = keys.get(key);
+                if (list == null)
+                {
+                    list = new ArrayList<IEntityProperty>();
+                    keys.put(key, list);
+                }
+                list.add(property);
+            }
+        }
+        return keys;
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/css/openbis.css b/openbis/source/java/ch/systemsx/cisd/openbis/public/css/openbis.css
index 9dc50e3b9689d9a1393702afa9140e34411fdedf..4d3efde91fa086298254977a63aea3d4f455931c 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/public/css/openbis.css
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/css/openbis.css
@@ -95,6 +95,11 @@ body,div,td,.default-text {
 	background-color: #dddddd;
 }
 
+.properties-sub-section {
+  background-color: #fff;
+  font-weight: normal;
+}
+
 /*****************************
  * MainTabPanel
  *****************************/
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/ParentsPropertiesSectionBuilderTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/ParentsPropertiesSectionBuilderTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcc83ad0f543888b51f4cb71f6e6d1e19be09c7f
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/plugin/generic/client/web/client/application/sample/ParentsPropertiesSectionBuilderTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 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.generic.client.web.client.application.sample;
+
+import java.util.List;
+import java.util.Map;
+
+import org.testng.AssertJUnit;
+import org.testng.annotations.Test;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataTypeCode;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.SampleBuilder;
+
+/**
+ * @author Franz-Josef Elmer
+ */
+public class ParentsPropertiesSectionBuilderTest extends AssertJUnit
+{
+    @Test
+    public void testNoSample()
+    {
+        ParentsPropertiesSectionBuilder builder = new ParentsPropertiesSectionBuilder();
+
+        Map<String, List<IEntityProperty>> sections = builder.getSections();
+
+        assertEquals("{}", sections.toString());
+    }
+
+    @Test
+    public void testSingleSample()
+    {
+        ParentsPropertiesSectionBuilder builder = new ParentsPropertiesSectionBuilder();
+
+        builder.addParent(new SampleBuilder("/S/S1").property("answer", "42").getSample());
+        Map<String, List<IEntityProperty>> sections = builder.getSections();
+
+        assertEquals("{Properties of /S/S1=[answer: 42]}", sections.toString());
+    }
+
+    @Test
+    public void testTwoSamplesWithNoCommonProperties()
+    {
+        ParentsPropertiesSectionBuilder builder = new ParentsPropertiesSectionBuilder();
+
+        builder.addParent(new SampleBuilder("/S/S1").property("answer", "43").getSample());
+        builder.addParent(new SampleBuilder("/S/S2").property("answer", "42")
+                .property("question", "6 x 7").getSample());
+        Map<String, List<IEntityProperty>> sections = builder.getSections();
+
+        assertEquals("{Properties of /S/S1=[answer: 43], "
+                + "Properties of /S/S2=[answer: 42, question: 6 x 7]}", sections.toString());
+    }
+
+    @Test
+    public void testTwoSamplesWithOneCommonProperties()
+    {
+        ParentsPropertiesSectionBuilder builder = new ParentsPropertiesSectionBuilder();
+
+        builder.addParent(new SampleBuilder("/S/S1").property("answer", "42").getSample());
+        builder.addParent(new SampleBuilder("/S/S2").property("answer", "42")
+                .property("question", "6 x 7").getSample());
+        Map<String, List<IEntityProperty>> sections = builder.getSections();
+
+        assertEquals("{Properties common by all parents=[answer: 42], "
+                + "Properties of /S/S2=[question: 6 x 7]}", sections.toString());
+    }
+
+    @Test
+    public void testThreeSamplesWithtwoCommonProperties()
+    {
+        ParentsPropertiesSectionBuilder builder = new ParentsPropertiesSectionBuilder();
+
+        SampleBuilder s1 =
+                new SampleBuilder("/S/S1").property("answer", "42").property("question", "6 x 7");
+        s1.property("property").type(DataTypeCode.INTEGER).value(101);
+        builder.addParent(s1.getSample());
+        SampleBuilder s2 =
+                new SampleBuilder("/S/S2").property("question", "6 x 7").property("answer", "42");
+        s2.property("property", "101");
+        builder.addParent(s2.getSample());
+        SampleBuilder s3 =
+                new SampleBuilder("/S/S3").property("question", "6 x 7").property("answer", "42");
+        s3.property("property", "101");
+        builder.addParent(s3.getSample());
+        Map<String, List<IEntityProperty>> sections = builder.getSections();
+
+        assertEquals("{Properties common by all parents=[answer: 42, question: 6 x 7], "
+                + "Properties of /S/S1=[property: 101], " + "Properties of /S/S2=[property: 101], "
+                + "Properties of /S/S3=[property: 101]}", sections.toString());
+    }
+}