diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/AbstractEntityDeliverer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/AbstractEntityDeliverer.java
index 6acd9428bfdff66e97c2b023f1a92966c6e74bb3..75e9c14e8c141f6126ce0d71f547baa861500b55 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/AbstractEntityDeliverer.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/AbstractEntityDeliverer.java
@@ -179,6 +179,11 @@ abstract class AbstractEntityDeliverer<T>
         addAttribute(writer, attributeName, value, v -> v);
     }
 
+    protected void addAttribute(XMLStreamWriter writer, String attributeName, Boolean value) throws XMLStreamException
+    {
+        addAttribute(writer, attributeName, value, v -> String.valueOf(v));
+    }
+    
     protected <O> void addAttribute(XMLStreamWriter writer, String attributeName, O object, Function<O, String> mapper) throws XMLStreamException
     {
         if (object != null)
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceRequestHandler.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceRequestHandler.java
index 9ffb2d846ac2a6524675f8bf2100386c47ef4180..03ee078bdc9045455506f61fdcba4295f868abf0 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceRequestHandler.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/DataSourceRequestHandler.java
@@ -42,6 +42,7 @@ import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSet;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.Space;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.fetchoptions.SpaceFetchOptions;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.space.search.SpaceSearchCriteria;
+import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.common.ServiceFinderUtils;
 import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.common.logging.LogCategory;
 import ch.systemsx.cisd.common.logging.LogFactory;
@@ -50,6 +51,9 @@ import ch.systemsx.cisd.openbis.dss.generic.server.oaipmh.IRequestHandler;
 import ch.systemsx.cisd.openbis.dss.generic.shared.DataSourceQueryService;
 import ch.systemsx.cisd.openbis.dss.generic.shared.IHierarchicalContentProvider;
 import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
+import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IMasterDataRegistrationTransaction;
+import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.EncapsulatedCommonServer;
+import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.MasterDataRegistrationService;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SessionContextDTO;
 
 /**
@@ -106,6 +110,7 @@ public class DataSourceRequestHandler implements IRequestHandler
         materialDeliverer = new MaterialDeliverer(deliveryContext);
         sampleDeliverer = new SampleDeliverer(deliveryContext);
         projectDeliverer = new ProjectDeliverer(deliveryContext);
+        String openBisServerUrl = ServiceProvider.getConfigProvider().getOpenBisServerUrl();
         masterDataDeliverer = new MasterDataDeliverer(deliveryContext);
     }
 
diff --git a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/MasterDataDeliverer.java b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/MasterDataDeliverer.java
index e604e0b057e6691616c436d8b5cb79d7aa201e12..c3ffae1048fdac0c98275bb8908e288cc7b9dcfc 100644
--- a/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/MasterDataDeliverer.java
+++ b/datastore_server/source/java/ch/ethz/sis/openbis/generic/server/dss/plugins/sync/datasource/MasterDataDeliverer.java
@@ -16,18 +16,72 @@
 
 package ch.ethz.sis.openbis.generic.server.dss.plugins.sync.datasource;
 
+import static ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant.INTERNAL_NAMESPACE_PREFIX;
+
 import java.util.Date;
+import java.util.List;
 import java.util.Set;
 
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICodeHolder;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IDescriptionHolder;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.IPropertyAssignmentsHolder;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.DataSetType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.fetchoptions.DataSetTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.search.DataSetTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.entitytype.EntityKind;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.ExperimentType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.fetchoptions.ExperimentTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.search.ExperimentTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.externaldms.ExternalDms;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.externaldms.fetchoptions.ExternalDmsFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.externaldms.search.ExternalDmsSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.MaterialType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.fetchoptions.MaterialTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.search.MaterialTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.plugin.Plugin;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.plugin.fetchoptions.PluginFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.plugin.search.PluginSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyAssignment;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.PropertyType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.fetchoptions.PropertyTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.property.search.PropertyTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.SampleType;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.fetchoptions.SampleTypeFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.search.SampleTypeSearchCriteria;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.Vocabulary;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.VocabularyTerm;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.fetchoptions.VocabularyFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.vocabulary.search.VocabularySearchCriteria;
+import ch.ethz.sis.openbis.generic.server.dss.plugins.sync.common.ServiceFinderUtils;
+import ch.systemsx.cisd.common.shared.basic.string.CommaSeparatedListBuilder;
+import ch.systemsx.cisd.openbis.dss.generic.shared.ServiceProvider;
+import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.DataType;
+import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IFileFormatTypeImmutable;
+import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.IMasterDataRegistrationTransaction;
+import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.EncapsulatedCommonServer;
+import ch.systemsx.cisd.openbis.generic.server.jython.api.v1.impl.MasterDataRegistrationService;
+import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
+import ch.systemsx.cisd.openbis.generic.shared.basic.CodeConverter;
+
 /**
  * @author Franz-Josef Elmer
- *
  */
 public class MasterDataDeliverer extends AbstractEntityDeliverer<Object>
 {
+    private static final VocabularySearchCriteria VOCABULARY_SEARCH_CRITERIA = new VocabularySearchCriteria();
+
+    private static final PropertyTypeSearchCriteria PROPERTY_TYPE_SEARCH_CRITERIA = new PropertyTypeSearchCriteria();
+
+    private static final ExperimentTypeSearchCriteria EXPERIMENT_TYPE_SEARCH_CRITERIA = new ExperimentTypeSearchCriteria();
+
+    private static final MaterialTypeSearchCriteria MATERIAL_TYPE_SEARCH_CRITERIA = new MaterialTypeSearchCriteria();
+
+    private static final SampleTypeSearchCriteria SAMPLE_TYPE_SEARCH_CRITERIA = new SampleTypeSearchCriteria();
+
+    private static final DataSetTypeSearchCriteria DATA_SET_TYPE_SEARCH_CRITERIA = new DataSetTypeSearchCriteria();
 
     MasterDataDeliverer(DeliveryContext context)
     {
@@ -40,6 +94,315 @@ public class MasterDataDeliverer extends AbstractEntityDeliverer<Object>
         startUrlElement(writer);
         addLocation(writer, "MASTER_DATA", "MASTER_DATA");
         addLastModificationDate(writer, requestTimestamp);
+        writer.writeStartElement("xmd:masterData");
+        addFileFormatTypes(writer, sessionToken);
+        addValidationPlugins(writer, sessionToken);
+        addVocabularies(writer, sessionToken);
+        addPropertyTypes(writer, sessionToken);
+        addSampleTypes(writer, sessionToken);
+        addExperimentTypes(writer, sessionToken);
+        addDataSetTypes(writer, sessionToken);
+        addMaterialTypes(writer, sessionToken);
+        addExternalDataManagementSystems(writer, sessionToken);
+        writer.writeEndElement();
+        writer.writeEndElement();
+    }
+
+    private void addFileFormatTypes(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        String openBisServerUrl = ServiceProvider.getConfigProvider().getOpenBisServerUrl();
+        EncapsulatedCommonServer encapsulatedServer = ServiceFinderUtils.getEncapsulatedCommonServer(sessionToken, openBisServerUrl);
+        MasterDataRegistrationService service = new MasterDataRegistrationService(encapsulatedServer);
+        IMasterDataRegistrationTransaction masterDataRegistrationTransaction = service.transaction();
+        List<IFileFormatTypeImmutable> fileFormatTypes = masterDataRegistrationTransaction.listFileFormatTypes();
+        if (fileFormatTypes.size() > 0)
+        {
+            writer.writeStartElement("xmd:fileFormatTypes");
+            for (IFileFormatTypeImmutable fileFormatType : fileFormatTypes)
+            {
+                writer.writeStartElement("xmd:fileFormatType");
+                addAttribute(writer, "code", fileFormatType.getCode());
+                addAttribute(writer, "description", fileFormatType.getDescription());
+                writer.writeEndElement();
+            }
+            writer.writeEndElement();
+        }
+    }
+
+    private void addValidationPlugins(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        PluginFetchOptions fetchOptions = new PluginFetchOptions();
+        fetchOptions.withScript();
+        List<Plugin> plugins = context.getV3api().searchPlugins(sessionToken, new PluginSearchCriteria(), fetchOptions).getObjects();
+        if (plugins.isEmpty())
+        {
+            return;
+        }
+        writer.writeStartElement("xmd:validationPlugins");
+        for (Plugin plugin : plugins)
+        {
+            writer.writeStartElement("xmd:validationPlugin");
+            addAttribute(writer, "description", plugin.getDescription());
+            addAttribute(writer, "entityKind", getEntityKind(plugin));
+            addAttribute(writer, "isAvailable", String.valueOf(plugin.isAvailable()));
+            addAttribute(writer, "name", plugin.getName());
+            addAttribute(writer, "type", plugin.getPluginType(), t -> t.toString());
+            if (plugin.getScript() != null)
+            {
+                writer.writeCData(plugin.getScript());
+            }
+            writer.writeEndElement();
+        }
+        writer.writeEndElement();
+    }
+
+    private String getEntityKind(Plugin plugin)
+    {
+        String entityKind = "All";
+        Set<EntityKind> entityKinds = plugin.getEntityKinds();
+        if (entityKinds != null)
+        {
+            CommaSeparatedListBuilder builder = new CommaSeparatedListBuilder();
+            for (EntityKind kind : entityKinds)
+            {
+                builder.append(kind.toString());
+            }
+            entityKind = builder.toString();
+        }
+        return entityKind;
+    }
+
+    private void addVocabularies(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        VocabularyFetchOptions fetchOptions = new VocabularyFetchOptions();
+        fetchOptions.withTerms();
+        List<Vocabulary> vocabularies = context.getV3api().searchVocabularies(sessionToken, VOCABULARY_SEARCH_CRITERIA, fetchOptions).getObjects();
+        if (vocabularies.isEmpty())
+        {
+            return;
+        }
+        writer.writeStartElement("xmd:controlledVocabularies");
+        for (Vocabulary vocabulary : vocabularies)
+        {
+            writer.writeStartElement("xmd:controlledVocabulary");
+            String code = vocabulary.isInternalNameSpace()
+                    && vocabulary.getCode().startsWith(INTERNAL_NAMESPACE_PREFIX) ? CodeConverter.tryToDatabase(vocabulary.getCode())
+                            : vocabulary.getCode();
+            addAttribute(writer, "chosenFromList", String.valueOf(vocabulary.isChosenFromList()));
+            addAttribute(writer, "code", code);
+            addAttribute(writer, "description", vocabulary.getDescription());
+            addAttribute(writer, "internalNamespace", String.valueOf(vocabulary.isInternalNameSpace()));
+            addAttribute(writer, "managedInternally", String.valueOf(vocabulary.isManagedInternally()));
+            addAttribute(writer, "urlTemplate", vocabulary.getUrlTemplate());
+
+            for (VocabularyTerm term : vocabulary.getTerms())
+            {
+                writer.writeStartElement("xmd:term");
+                addAttribute(writer, "code", term.getCode());
+                addAttribute(writer, "description", term.getDescription());
+                addAttribute(writer, "label", term.getLabel());
+                addAttribute(writer, "ordinal", String.valueOf(term.getOrdinal()));
+                addAttribute(writer, "url", vocabulary.getUrlTemplate(),
+                        t -> t.replaceAll(BasicConstant.DEPRECATED_VOCABULARY_URL_TEMPLATE_TERM_PATTERN, code)
+                                .replaceAll(BasicConstant.VOCABULARY_URL_TEMPLATE_TERM_PATTERN, code));
+                writer.writeEndElement();
+            }
+            writer.writeEndElement();
+        }
+        writer.writeEndElement();
+    }
+
+    private void addPropertyTypes(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        PropertyTypeFetchOptions fetchOptions = new PropertyTypeFetchOptions();
+        fetchOptions.withMaterialType();
+        fetchOptions.withVocabulary();
+        List<PropertyType> propertyTypes =
+                context.getV3api().searchPropertyTypes(sessionToken, PROPERTY_TYPE_SEARCH_CRITERIA, fetchOptions).getObjects();
+        if (propertyTypes.isEmpty())
+        {
+            return;
+        }
+        writer.writeStartElement("xmd:propertyTypes");
+
+        for (PropertyType propertyType : propertyTypes)
+        {
+            Boolean internalNameSpace = propertyType.isInternalNameSpace();
+            String code =
+                    (internalNameSpace && propertyType.getCode().startsWith(INTERNAL_NAMESPACE_PREFIX))
+                            ? CodeConverter.tryToDatabase(propertyType.getCode())
+                            : propertyType.getCode();
+            writer.writeStartElement("xmd:propertyType");
+            addAttribute(writer, "code", code);
+            addAttribute(writer, "dataType", propertyType.getDataType(), t -> t.name());
+            addAttribute(writer, "description", propertyType.getDescription());
+            addAttribute(writer, "internalNamespace", internalNameSpace);
+            addAttribute(writer, "label", propertyType.getLabel());
+            addAttribute(writer, "managedInternally", propertyType.isManagedInternally());
+            if (propertyType.getDataType().name().equals(DataType.CONTROLLEDVOCABULARY.name()))
+            {
+                addAttribute(writer, "vocabulary", propertyType.getVocabulary(), v -> v.getCode());
+            } else if (propertyType.getDataType().name().equals(DataType.MATERIAL.name()))
+            {
+                if (propertyType.getMaterialType() != null)
+                {
+                    addAttribute(writer, "material", propertyType.getMaterialType(), t -> t.getCode());
+                } else
+                {
+                    // for properties like "inhibitor_of" where it is of Material of Any Type
+                    addAttribute(writer, "material", "");
+                }
+            }
+            writer.writeEndElement();
+        }
+        writer.writeEndElement();
+    }
+
+    private void addSampleTypes(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        SampleTypeFetchOptions fetchOptions = new SampleTypeFetchOptions();
+        fetchOptions.withPropertyAssignments().withPropertyType();
+        fetchOptions.withPropertyAssignments().withPlugin();
+        fetchOptions.withValidationPlugin();
+        List<SampleType> types = context.getV3api().searchSampleTypes(sessionToken, SAMPLE_TYPE_SEARCH_CRITERIA, fetchOptions).getObjects();
+        if (types.isEmpty())
+        {
+            return;
+        }
+        writer.writeStartElement("xmd:objectTypes");
+        for (SampleType type : types)
+        {
+            writeTypeElement(writer, "xmd:objectType", type);
+            addAttribute(writer, "autoGeneratedCode", type.isAutoGeneratedCode());
+            addAttribute(writer, "generatedCodePrefix", type.getGeneratedCodePrefix());
+            addAttribute(writer, "listable", type.isListable());
+            addAttribute(writer, "showContainer", type.isShowContainer());
+            addAttribute(writer, "showParentMetadata", type.isShowParentMetadata());
+            addAttribute(writer, "showParents", type.isShowParents());
+            addAttribute(writer, "subcodeUnique", type.isSubcodeUnique());
+            addAttribute(writer, "validationPlugin", type.getValidationPlugin(), p -> p.getName());
+            addPropertyAssignments(writer, type.getPropertyAssignments());
+            writer.writeEndElement();
+        }
+        writer.writeEndElement();
+    }
+
+    private void addExperimentTypes(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        ExperimentTypeFetchOptions fetchOptions = new ExperimentTypeFetchOptions();
+        fetchOptions.withPropertyAssignments().withPropertyType();
+        fetchOptions.withPropertyAssignments().withPlugin();
+        fetchOptions.withValidationPlugin();
+        List<ExperimentType> types =
+                context.getV3api().searchExperimentTypes(sessionToken, EXPERIMENT_TYPE_SEARCH_CRITERIA, fetchOptions).getObjects();
+        if (types.isEmpty())
+        {
+            return;
+        }
+        writer.writeStartElement("xmd:collectionTypes");
+        for (ExperimentType type : types)
+        {
+            writeTypeElement(writer, "xmd:collectionType", type);
+            addAttribute(writer, "validationPlugin", type.getValidationPlugin(), p -> p.getName());
+            addPropertyAssignments(writer, type.getPropertyAssignments());
+            writer.writeEndElement();
+        }
+        writer.writeEndElement();
+    }
+
+    private void addDataSetTypes(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        DataSetTypeFetchOptions fetchOptions = new DataSetTypeFetchOptions();
+        fetchOptions.withPropertyAssignments().withPropertyType();
+        fetchOptions.withPropertyAssignments().withPlugin();
+        fetchOptions.withValidationPlugin();
+        List<DataSetType> types = context.getV3api().searchDataSetTypes(sessionToken, DATA_SET_TYPE_SEARCH_CRITERIA, fetchOptions).getObjects();
+        if (types.isEmpty())
+        {
+            return;
+        }
+        writer.writeStartElement("xmd:dataSetTypes");
+        for (DataSetType type : types)
+        {
+            writeTypeElement(writer, "xmd:dataSetType", type);
+            addAttribute(writer, "deletionDisallowed", type.isDisallowDeletion());
+            addAttribute(writer, "mainDataSetPath", type.getMainDataSetPath());
+            addAttribute(writer, "mainDataSetPattern", type.getMainDataSetPattern());
+            addAttribute(writer, "validationPlugin", type.getValidationPlugin(), p -> p.getName());
+            addPropertyAssignments(writer, type.getPropertyAssignments());
+            writer.writeEndElement();
+        }
+        writer.writeEndElement();
+    }
+
+    private void addMaterialTypes(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        MaterialTypeFetchOptions fetchOptions = new MaterialTypeFetchOptions();
+        fetchOptions.withPropertyAssignments().withPropertyType();
+        fetchOptions.withPropertyAssignments().withPlugin();
+        fetchOptions.withValidationPlugin();
+        List<MaterialType> types = context.getV3api().searchMaterialTypes(sessionToken, MATERIAL_TYPE_SEARCH_CRITERIA, fetchOptions).getObjects();
+        if (types.isEmpty())
+        {
+            return;
+        }
+        writer.writeStartElement("xmd:materialTypes");
+        for (MaterialType type : types)
+        {
+            writeTypeElement(writer, "xmd:materialType", type);
+            addAttribute(writer, "validationPlugin", type.getValidationPlugin(), p -> p.getName());
+            addPropertyAssignments(writer, type.getPropertyAssignments());
+            writer.writeEndElement();
+        }
+        writer.writeEndElement();
+    }
+
+    private void addExternalDataManagementSystems(XMLStreamWriter writer, String sessionToken) throws XMLStreamException
+    {
+        ExternalDmsSearchCriteria searchCriteria = new ExternalDmsSearchCriteria();
+        ExternalDmsFetchOptions fetchOptions = new ExternalDmsFetchOptions();
+        List<ExternalDms> externalDataManagementSystems =
+                context.getV3api().searchExternalDataManagementSystems(sessionToken, searchCriteria, fetchOptions).getObjects();
+        if (externalDataManagementSystems.isEmpty() == false)
+        {
+            writer.writeStartElement("xmd:externalDataManagementSystems");
+            for (ExternalDms externalDms : externalDataManagementSystems)
+            {
+                writer.writeStartElement("xmd:externalDataManagementSystem");
+                addAttribute(writer, "address", externalDms.getAddress());
+                addAttribute(writer, "addressType", externalDms.getAddressType(), t -> t.toString());
+                addAttribute(writer, "code", externalDms.getCode());
+                addAttribute(writer, "label", externalDms.getLabel());
+                writer.writeEndElement();
+            }
+            writer.writeEndElement();
+        }
+    }
+
+    private <T extends ICodeHolder & IDescriptionHolder & IPropertyAssignmentsHolder> void writeTypeElement(
+            XMLStreamWriter writer, String elementType, T type) throws XMLStreamException
+    {
+        writer.writeStartElement(elementType);
+        addAttribute(writer, "code", type.getCode());
+        addAttribute(writer, "description", type.getDescription());
+    }
+
+    private void addPropertyAssignments(XMLStreamWriter writer, List<PropertyAssignment> propertyAssignments) throws XMLStreamException
+    {
+        writer.writeStartElement("xmd:propertyAssignments");
+        for (PropertyAssignment propertyAssignment : propertyAssignments)
+        {
+            writer.writeStartElement("xmd:propertyAssignment");
+            addAttribute(writer, "mandatory", propertyAssignment.isMandatory());
+            addAttribute(writer, "ordinal", propertyAssignment.getOrdinal(), i -> String.valueOf(i));
+            addAttribute(writer, "plugin", propertyAssignment.getPlugin(), p -> p.getPermId().getPermId());
+            addAttribute(writer, "pluginType", propertyAssignment.getPlugin(), p -> p.getPluginType().toString());
+            addAttribute(writer, "propertyTypeCode", propertyAssignment.getPropertyType(), t -> t.getCode());
+            addAttribute(writer, "section", propertyAssignment.getSection());
+            addAttribute(writer, "showInEdit", propertyAssignment.isShowInEditView());
+            addAttribute(writer, "showRawValueInForms", propertyAssignment.isShowRawValueInForms());
+            writer.writeEndElement();
+        }
         writer.writeEndElement();
     }
 
diff --git a/openbis_standard_technologies/dist/core-plugins/openbis-sync/1/dss/services/resource-sync/plugin.properties b/openbis_standard_technologies/dist/core-plugins/openbis-sync/1/dss/services/resource-sync/plugin.properties
index 232440c704f58db5ec517ba20e5ede9e08ba24d2..88da3b4479560fbf18c9b16dd32f7c19ba1a3a9e 100644
--- a/openbis_standard_technologies/dist/core-plugins/openbis-sync/1/dss/services/resource-sync/plugin.properties
+++ b/openbis_standard_technologies/dist/core-plugins/openbis-sync/1/dss/services/resource-sync/plugin.properties
@@ -1,6 +1,6 @@
 class = ch.systemsx.cisd.openbis.dss.generic.server.oaipmh.OaipmhServlet
 path = /datastore_server/re-sync/*
-request-handler = ch.ethz.sis.openbis.generic.server.dss.plugins.sync.datasource.ResourceSyncRequestHandler
+request-handler = ch.ethz.sis.openbis.generic.server.dss.plugins.sync.datasource.DataSourceRequestHandler
 request-handler.script-path = data-source-servlet.py
 request-handler.published-spaces = ${published-spaces}
 request-handler.temp-dir = ${root-dir}/sync