diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/common/EntityRetriever.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/common/EntityRetriever.java
index 510b319354f25287fbfd3e93349e52376f4c6c51..9b0bb4e473eacffa3b3b2543db745027367e3e84 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/common/EntityRetriever.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/common/EntityRetriever.java
@@ -112,6 +112,11 @@ public class EntityRetriever
         graph = new EntityGraph<Node<?>>();
 
         // add shared samples
+        /*
+         * adding shared samples to the entity graph for a space means if we are synching from multiple spaces, each entity graph (for each space)
+         * will have the shared entity. When we add them to the RL (Resource List) in the data source servlet, any duplicate will throw an error when
+         * using the Resync library. To work around this we catch the duplicate exceptions where a shared sample is involved.
+         */
         findSharedSamples();
 
         // build the graph for the space from top-down starting from projects
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/config/ConfigReader.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/config/ConfigReader.java
index 6c8009cceae905fa8e6dda6459c62f846150f27a..eb969e940d48c315f3ac91563f9e756ed4d19ac7 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/config/ConfigReader.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/config/ConfigReader.java
@@ -31,6 +31,8 @@ import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.commons.lang3.StringUtils;
+
 import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException;
 
 public class ConfigReader
@@ -155,15 +157,11 @@ public class ConfigReader
             throw new ConfigurationFailureException("Section '" + section + " does not exist.");
         }
         String val = map.get(key);
-        if (val == null)
-        {
-            return null;
-        }
-        if (val.trim().equals("") == true)
+        if (StringUtils.isBlank(val) == true)
         {
             return null;
         }
-        return val;
+        return val.trim();
     }
 
     public int getInt(String section, String key, int defaultvalue, boolean mandatory)
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java
index ab0aaaa30e191bde84f75df3ce6a6339db6ef711..54524d4f48d78b735f959d70097dfca063048631 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/EntitySynchronizer.java
@@ -37,6 +37,7 @@ import java.util.Set;
 import org.apache.commons.codec.binary.Hex;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.log4j.Logger;
 import org.w3c.dom.Document;
 
@@ -188,7 +189,7 @@ public class EntitySynchronizer
         operationLog.info("parsing the resource list xml document");
         String dataSourcePrefix = config.getDataSourceAlias();
         INameTranslator nameTranslator = null;
-        if (dataSourcePrefix != null && dataSourcePrefix.trim().equals("") == false)
+        if (StringUtils.isBlank(dataSourcePrefix) == false)
         {
             nameTranslator = new PrefixBasedNameTranslator(dataSourcePrefix);
         }
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/ResourceListParser.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/ResourceListParser.java
index 891a44c4cc31e978929fa433c18aafca26f81031..4e4756b2ed9a8877ab18a528f2a7a271c6ffdefd 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/ResourceListParser.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/harvester/synchronizer/ResourceListParser.java
@@ -35,6 +35,7 @@ import javax.xml.xpath.XPathExpression;
 import javax.xml.xpath.XPathExpressionException;
 import javax.xml.xpath.XPathFactory;
 
+import org.apache.commons.lang.StringUtils;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -44,10 +45,10 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetKind;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.Connection;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.IncomingDataSet;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.IncomingExperiment;
-import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.MasterData;
-import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.MaterialWithLastModificationDate;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.IncomingProject;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.IncomingSample;
+import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.MasterData;
+import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.ResourceListParserData.MaterialWithLastModificationDate;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.translator.DefaultNameTranslator;
 import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.harvester.synchronizer.translator.INameTranslator;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetType;
@@ -273,49 +274,63 @@ public class ResourceListParser
     private void parseDataSetMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate)
     {
         String code = extractCode(xdNode);
-        String sample = extractAttribute(xdNode, "sample");
-        String experiment = extractAttribute(xdNode, "experiment");
+        String sample = extractAttribute(xdNode, "sample", true);
+        String experiment = extractAttribute(xdNode, "experiment", true);
         String type = extractType(xdNode);
         String dsKind = extractAttribute(xdNode, "dsKind");
-        NewExternalData ds = new NewExternalData();
+        NewExternalData ds = null;
         if (dsKind.equals(DataSetKind.CONTAINER.toString()))
         {
             ds = new NewContainerDataSet();
-            ds.setCode(code);
-            ds.setDataSetType(new DataSetType(type));
-            ds.setDataStoreCode(this.dataStoreCode);
-            if (sample.trim().equals("") == false)
-            {
-                ds.setSampleIdentifierOrNull(getSampleIdentifier(sample));
-            }
-            if (experiment.trim().equals("") == false)
-            {
-                ds.setExperimentIdentifierOrNull(getExperimentIdentifier(experiment));
-            }
         }
         else if (dsKind.equals(DataSetKind.PHYSICAL.toString()))
         {
-            ds.setCode(code);
-            ds.setDataSetType(new DataSetType(type));
-            ds.setDataStoreCode(this.dataStoreCode);
-            if (sample.trim().equals("") == false)
-            {
-                ds.setSampleIdentifierOrNull(getSampleIdentifier(sample));
-            }
-            if (experiment.trim().equals("") == false)
-            {
-                ds.setExperimentIdentifierOrNull(getExperimentIdentifier(experiment));
-            }
+            ds = new NewExternalData();
         }
+        // else if (dsKind.equals(DataSetKind.LINK.toString())) {
+        // ds = new NewLinkDataSet();
+        // ((NewLinkDataSet)ds).
+        // }
+        else
+        {
+            throw new IllegalArgumentException(dsKind + " data sets are currently not supported");
+        }
+        ds.setCode(code);
+        ds.setDataSetType(new DataSetType(type));
+        ds.setDataStoreCode(this.dataStoreCode);
+
+        ds.setSampleIdentifierOrNull(getSampleIdentifier(sample));
+        ds.setExperimentIdentifierOrNull(getExperimentIdentifier(experiment));
+
         IncomingDataSet incomingDataSet = data.new IncomingDataSet(ds, lastModificationDate);
         data.getDataSetsToProcess().put(permId, incomingDataSet);
         incomingDataSet.setConnections(parseConnections(xpath, xdNode));
         ds.setDataSetProperties(parseDataSetProperties(xpath, xdNode));
     }
 
-    private String extractAttribute(Node xdNode, String attrName)
+    private String extractAttribute(Node xdNode, String attrName, boolean nullAllowed)
+    {
+        String val = xdNode.getAttributes().getNamedItem(attrName).getTextContent();
+        if (StringUtils.isBlank(val) == true)
+        {
+            if (nullAllowed == false)
+            {
+                throw new IllegalArgumentException(attrName + " cannot be empty in Resource List");
+            }
+            else
+            {
+                return null;
+            }
+        }
+        else
+        {
+            return val.trim();
+        }
+    }
+
+    private String extractAttribute(Node xdNode, String attrName) throws IllegalArgumentException
     {
-        return xdNode.getAttributes().getNamedItem(attrName).getTextContent();
+        return extractAttribute(xdNode, attrName, false);
     }
 
     private String extractCode(Node xdNode)
@@ -325,15 +340,23 @@ public class ResourceListParser
 
     private SampleIdentifier getSampleIdentifier(String sampleIdentifierStr)
     {
+        if (sampleIdentifierStr == null)
+        {
+            return null;
+        }
         SampleIdentifier sampleIdentifier = SampleIdentifierFactory.parse(sampleIdentifierStr);
         SpaceIdentifier spaceLevel = sampleIdentifier.getSpaceLevel();
         String originalSpaceCode = spaceLevel.getSpaceCode();
         return new SampleIdentifier(new SpaceIdentifier(nameTranslator.translate(originalSpaceCode)), sampleIdentifier.getSampleCode());
     }
 
-    private ExperimentIdentifier getExperimentIdentifier(String experiment)
+    private ExperimentIdentifier getExperimentIdentifier(String experimentIdentifierStr)
     {
-        ExperimentIdentifier experimentIdentifier = ExperimentIdentifierFactory.parse(experiment);
+        if (experimentIdentifierStr == null)
+        {
+            return null;
+        }
+        ExperimentIdentifier experimentIdentifier = ExperimentIdentifierFactory.parse(experimentIdentifierStr);
         String originalSpaceCode = experimentIdentifier.getSpaceCode();
         String projectCode = experimentIdentifier.getProjectCode();
         String expCode = experimentIdentifier.getExperimentCode();
@@ -345,9 +368,9 @@ public class ResourceListParser
 
         String code = extractCode(xdNode);
         String desc = xdNode.getAttributes().getNamedItem("desc").getTextContent();
-        String space = extractSpace(xdNode);
-        // TODO is there a better way to create project identifier below?
-        NewProject newProject = new NewProject("/" + nameTranslator.translate(space) + "/" + code, desc);
+        String space = extractSpace(xdNode, false);
+        ProjectIdentifier projectIdentifier = createProjectIdentifier(code, space);
+        NewProject newProject = new NewProject(projectIdentifier.toString(), desc);
         newProject.setPermID(permId);
         IncomingProject incomingProject =
                 data.new IncomingProject(newProject, lastModificationDate);
@@ -356,6 +379,26 @@ public class ResourceListParser
         incomingProject.setHasAttachments(hasAttachments(xpath, xdNode));
     }
 
+    private ProjectIdentifier createProjectIdentifier(String code, String space)
+    {
+        return new ProjectIdentifier(createSpaceIdentifier(space), code);
+    }
+
+    private SampleIdentifier createSampleIdentifier(String code, String space)
+    {
+        if (space == null)
+        {
+            return new SampleIdentifier(nameTranslator.translate(code));
+        }
+        SpaceIdentifier spaceIdentifier = createSpaceIdentifier(space);
+        return new SampleIdentifier(spaceIdentifier, code);
+    }
+
+    private SpaceIdentifier createSpaceIdentifier(String space)
+    {
+        return new SpaceIdentifier(nameTranslator.translate(space));
+    }
+
     private void parseMaterialMetaData(XPath xpath, String permId, Node xdNode, Date lastModificationDate)
     {
         String code = extractCode(xdNode);
@@ -457,7 +500,7 @@ public class ResourceListParser
         String code = extractCode(xdNode);
         String type = extractType(xdNode);
         String project = extractAttribute(xdNode, "project");
-        String space = extractSpace(xdNode);
+        String space = extractSpace(xdNode, false);
         NewExperiment newExp = new NewExperiment("/" + nameTranslator.translate(space) + "/" + project + "/" + code, type);
         newExp.setPermID(permId);
         IncomingExperiment incomingExperiment = data.new IncomingExperiment(newExp, lastModificationDate);
@@ -471,15 +514,20 @@ public class ResourceListParser
     {
         String code = extractCode(xdNode);
         String type = extractType(xdNode);
-        String experiment = extractAttribute(xdNode, "experiment");
-        String space = extractSpace(xdNode);
+        String experiment = extractAttribute(xdNode, "experiment", true);
+        String space = extractSpace(xdNode, true);
         SampleType sampleType = new SampleType();
         sampleType.setCode(type);
 
-        NewSample newSample = new NewSample("/" + nameTranslator.translate(space) + "/" + code, sampleType, null, null,
-                experiment.trim().equals("") ? null : experiment, null, null, new IEntityProperty[0],
+        SampleIdentifier identifier = createSampleIdentifier(code, space);
+        NewSample newSample = new NewSample(identifier.toString(), sampleType, null, null,
+                experiment, null, null, new IEntityProperty[0],
                 new ArrayList<NewAttachment>());
         newSample.setPermID(permId);
+        if (space == null)
+        {
+            newSample.setDefaultSpaceIdentifier(null);
+        }
         IncomingSample incomingSample = data.new IncomingSample(newSample, lastModificationDate);
         data.getSamplesToProcess().put(permId, incomingSample);
         incomingSample.setHasAttachments(hasAttachments(xpath, xdNode));
@@ -492,10 +540,13 @@ public class ResourceListParser
         return extractAttribute(xdNode, "type");
     }
 
-    private String extractSpace(Node xdNode)
+    private String extractSpace(Node xdNode, boolean nullAllowed)
     {
-        String space = extractAttribute(xdNode, "space");
-        data.getHarvesterSpaceList().add(nameTranslator.translate(space));
+        String space = extractAttribute(xdNode, "space", nullAllowed);
+        if (space != null)
+        {
+            data.getHarvesterSpaceList().add(nameTranslator.translate(space));
+        }
         return space;
     }