diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetLister.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetLister.java
index 0e7f52f63c03c4ec9ca7d953845637ae5205e152..490f842d6de80f52297f1b61a9957e9361c4afb4 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetLister.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetLister.java
@@ -34,6 +34,9 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSetFetchOption;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSetFetchOptions;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.EntityRegistrationDetails;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.EntityRegistrationDetails.EntityRegistrationDetailsInitializer;
+import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
+import ch.systemsx.cisd.openbis.generic.shared.basic.BasicURLEncoder;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetKind;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.DatabaseInstanceIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifier;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.IdentifierHelper;
@@ -166,7 +169,17 @@ public class DataSetLister implements IDataSetLister
         DataSetInitializer initializer = new DataSetInitializer();
         initializer.setCode(dataSet.ds_code);
         initializer.setDataSetTypeCode(dataSet.dt_code);
-        initializer.setDataSetKind(dataSet.dt_data_set_kind);
+        initializer.setContainerDataSet(DataSetKind.CONTAINER.name().equals(
+                dataSet.dt_data_set_kind));
+        initializer.setLinkDataSet(DataSetKind.LINK.name().equals(dataSet.dt_data_set_kind));
+        if (initializer.isLinkDataSet())
+        {
+            initializer.setExternalDataSetCode(dataSet.ld_external_code);
+            initializer.setExternalDataSetLink(dataSet.edms_url_template == null ? null
+                    : dataSet.edms_url_template.replaceAll(
+                            BasicConstant.EXTERNAL_DMS_URL_TEMPLATE_CODE_PATTERN,
+                            BasicURLEncoder.encode(dataSet.ld_external_code)));
+        }
         initializer.setRegistrationDetails(createDataSetRegistrationDetails(dataSet));
         initializer.setExperimentIdentifier(experimentIdentifier.toString());
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetRecord.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetRecord.java
index 88f62649099d667c5b3364f972da30f17bcf60c0..9c8ceef58f8640dffd86bfe88b822a7fcfcfe15a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetRecord.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetRecord.java
@@ -70,4 +70,8 @@ public class DataSetRecord
 
     public Boolean die_is_original_source;
 
+    public String ld_external_code;
+
+    public String edms_url_template;
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/IDataSetListingQuery.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/IDataSetListingQuery.java
index bb1824627e8007a9b4b1d40f121f9d679768ae4c..33b81614895aff4dc896188cecfd5906819e6f5b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/IDataSetListingQuery.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/IDataSetListingQuery.java
@@ -41,9 +41,12 @@ public interface IDataSetListingQuery extends BaseQuery
             + " pe.first_name as pe_first_name, pe.last_name as pe_last_name, pe.email as pe_email, pe.user_id as pe_user_id,"
             + " mod.first_name as mod_first_name, mod.last_name as mod_last_name, mod.email as mod_email, mod.user_id as mod_user_id,"
             + " pre.code as pre_code, spe.code as spe_code, sps.code as sps_code,"
-            + " die.code as die_code, die.is_original_source as die_is_original_source"
+            + " die.code as die_code, die.is_original_source as die_is_original_source,"
+            + " ld.external_code as ld_external_code, edms.url_template as edms_url_template"
             + " from data ds inner join data_set_types dt on ds.dsty_id = dt.id"
             + " inner join experiments ex on ds.expe_id = ex.id"
+            + " left outer join link_data ld on ds.id = ld.data_id"
+            + " left outer join external_data_management_systems edms on ld.edms_id = edms.id"
             + " left outer join samples sa on ds.samp_id = sa.id"
             + " left outer join persons pe on ds.pers_id_registerer = pe.id"
             + " left outer join persons mod on ds.pers_id_modifier = mod.id"
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/Translator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/Translator.java
index bdfc9d112f384dcad3416e8f49e4dc6f676312cc..4936515df4613ffab48988c46bfda01f82e1dc80 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/Translator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/Translator.java
@@ -53,12 +53,15 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SampleFetchOption;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Vocabulary;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.Vocabulary.VocabularyInitializer;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.VocabularyTerm;
+import ch.systemsx.cisd.openbis.generic.shared.basic.BasicConstant;
+import ch.systemsx.cisd.openbis.generic.shared.basic.BasicURLEncoder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CodeWithRegistration;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.CodeWithRegistrationAndModificationDate;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ContainerDataSet;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataTypeCode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LinkDataSet;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Person;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy.RoleCode;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy.RoleLevel;
@@ -345,7 +348,7 @@ public class Translator
             initializer.putProperty(prop.getPropertyType().getCode(), prop.tryGetAsString());
         }
 
-        initializer.setDataSetKind(externalDatum.getDataSetKind().name());
+        initializer.setContainerDataSet(externalDatum.isContainer());
         if (externalDatum.isContainer())
         {
             // Recursively translate any contained data sets
@@ -359,6 +362,18 @@ public class Translator
             }
             initializer.setContainedDataSets(containedDataSetCodes);
         }
+        initializer.setLinkDataSet(externalDatum.isLinkData());
+        if (externalDatum.isLinkData())
+        {
+            LinkDataSet linkDataSet = externalDatum.tryGetAsLinkDataSet();
+            initializer.setExternalDataSetCode(linkDataSet.getExternalCode());
+            initializer.setExternalDataSetLink(linkDataSet.getExternalDataManagementSystem()
+                    .getUrlTemplate() == null ? null : linkDataSet
+                    .getExternalDataManagementSystem()
+                    .getUrlTemplate()
+                    .replaceAll(BasicConstant.EXTERNAL_DMS_URL_TEMPLATE_CODE_PATTERN,
+                            BasicURLEncoder.encode(linkDataSet.getExternalCode())));
+        }
 
         initializer.setRetrievedConnections(connectionsToGet);
         for (Connections connection : connectionsToGet)
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java
index 73a2cff78bc16cc8df0ce41faadbb0b4118e8ad4..0190536936ecddde7c63363bf83cdb3aa4e7f931 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/datasetlister/DatasetListerTest.java
@@ -302,11 +302,11 @@ public class DatasetListerTest extends AbstractDAOTest
                 .getExternalDataManagementSystem().getLabel());
         assertEquals("Test External openBIS instance", datasets.get(2).tryGetAsLinkDataSet()
                 .getExternalDataManagementSystem().getLabel());
-        assertEquals("http://example.edms.pl/code=${code}", datasets.get(0).tryGetAsLinkDataSet()
+        assertEquals("http://example.edms.pl/code=$code$", datasets.get(0).tryGetAsLinkDataSet()
                 .getExternalDataManagementSystem().getUrlTemplate());
-        assertEquals("http://example.edms.pl/code=${code}", datasets.get(1).tryGetAsLinkDataSet()
+        assertEquals("http://example.edms.pl/code=$code$", datasets.get(1).tryGetAsLinkDataSet()
                 .getExternalDataManagementSystem().getUrlTemplate());
-        assertEquals("http://www.openbis.ch/perm_id=${code}", datasets.get(2).tryGetAsLinkDataSet()
+        assertEquals("http://www.openbis.ch/perm_id=$code$", datasets.get(2).tryGetAsLinkDataSet()
                 .getExternalDataManagementSystem().getUrlTemplate());
         assertFalse(datasets.get(0).tryGetAsLinkDataSet().getExternalDataManagementSystem()
                 .isOpenBIS());
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetListerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetListerTest.java
index 829a3311ba43449b28b9837d69356cc08a1dbd3e..7595e78cae9001a89d86e3eb1bfdfafb2d5c8fb8 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetListerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/fetchoptions/datasetlister/DataSetListerTest.java
@@ -19,6 +19,7 @@ package ch.systemsx.cisd.openbis.generic.server.business.bo.fetchoptions.dataset
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
 
 import java.sql.SQLException;
 import java.util.ArrayList;
@@ -150,6 +151,32 @@ public class DataSetListerTest extends AbstractDAOTest
         lister.getDataSetMetaData(codes, fetchOptions);
     }
 
+    @Test
+    public void testGetDataSetMetaDataForLinkDataSets()
+    {
+        List<String> codes = new ArrayList<String>();
+        codes.add("20120628092259000-23");
+        codes.add("20120628092259000-24");
+        codes.add("20120628092259000-25");
+        DataSetFetchOptions fetchOptions = new DataSetFetchOptions();
+
+        List<DataSet> results = lister.getDataSetMetaData(codes, fetchOptions);
+
+        assertEquals(3, results.size());
+        assertTrue(results.get(0).isLinkDataSet());
+        assertTrue(results.get(1).isLinkDataSet());
+        assertTrue(results.get(2).isLinkDataSet());
+        assertFalse(results.get(0).isContainerDataSet());
+        assertFalse(results.get(1).isContainerDataSet());
+        assertFalse(results.get(2).isContainerDataSet());
+        assertEquals("CODE1", results.get(0).getExternalDataSetCode());
+        assertEquals("CODE2", results.get(1).getExternalDataSetCode());
+        assertEquals("CODE3", results.get(2).getExternalDataSetCode());
+        assertEquals("http://example.edms.pl/code=CODE1", results.get(0).getExternalDataSetLink());
+        assertEquals("http://example.edms.pl/code=CODE2", results.get(1).getExternalDataSetLink());
+        assertEquals("http://www.openbis.ch/perm_id=CODE3", results.get(2).getExternalDataSetLink());
+    }
+
     private static void sortDataSetsByCode(List<DataSet> dataSets)
     {
         Collections.sort(dataSets, new Comparator<DataSet>()
@@ -194,7 +221,8 @@ public class DataSetListerTest extends AbstractDAOTest
         assertEquals(expected.getExperimentIdentifier(), actual.getExperimentIdentifier());
         assertEquals(expected.getSampleIdentifierOrNull(), actual.getSampleIdentifierOrNull());
         assertEquals(expected.getDataSetTypeCode(), actual.getDataSetTypeCode());
-        assertEquals(expected.getDataSetKind(), actual.getDataSetKind());
+        assertEquals(expected.isContainerDataSet(), actual.isContainerDataSet());
+        assertEquals(expected.isLinkDataSet(), actual.isLinkDataSet());
         assertEqualsToRegistrationDetails(expected.getRegistrationDetails(),
                 expected.getRegistrationDetails());
 
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExternalDataManagementSystemDAOTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExternalDataManagementSystemDAOTest.java
index 8ccfe14c77ffdf7540ecfb8ce9fa3de766a98aa8..16c34507a80a1d444e3f2590a258a77fe072c04b 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExternalDataManagementSystemDAOTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/ExternalDataManagementSystemDAOTest.java
@@ -74,7 +74,7 @@ public class ExternalDataManagementSystemDAOTest extends AbstractDAOTest
                 assertEquals(1L, edms.getDatabaseInstance().getId().longValue());
                 assertEquals("DMS_1", edms.getCode());
                 assertEquals("Test EDMS", edms.getLabel());
-                assertEquals("http://example.edms.pl/code=${code}", edms.getUrlTemplate());
+                assertEquals("http://example.edms.pl/code=$code$", edms.getUrlTemplate());
                 assertFalse(edms.isOpenBIS());
             } else
             {
@@ -82,7 +82,7 @@ public class ExternalDataManagementSystemDAOTest extends AbstractDAOTest
                 assertEquals(1L, edms.getDatabaseInstance().getId().longValue());
                 assertEquals("DMS_2", edms.getCode());
                 assertEquals("Test External openBIS instance", edms.getLabel());
-                assertEquals("http://www.openbis.ch/perm_id=${code}", edms.getUrlTemplate());
+                assertEquals("http://www.openbis.ch/perm_id=$code$", edms.getUrlTemplate());
                 assertTrue(edms.isOpenBIS());
             }
         }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/TranslatorTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/TranslatorTest.java
index a33a8a632315cfad0a4e2f84be906246c1b3f5eb..1a278005778a5187de5ef6bec0a8dd2c58f00d96 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/TranslatorTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/TranslatorTest.java
@@ -27,14 +27,15 @@ import org.testng.annotations.Test;
 
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSet;
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.DataSet.Connections;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Experiment;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalDataManagementSystem;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.IEntityProperty;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Project;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Sample;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.ContainerDataSetBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.DataSetBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.ExperimentBuilder;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.LinkDataSetBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.SampleBuilder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.builders.SampleTypeBuilder;
 
@@ -49,15 +50,23 @@ public class TranslatorTest extends AssertJUnit
 
     private ContainerDataSetBuilder dsContainer;
 
+    private LinkDataSetBuilder dsLink;
+
     private Experiment experiment;
 
     private Sample sample;
 
     private Project project;
 
+    private ExternalDataManagementSystem edms;
+
     @BeforeMethod
     public void setUp()
     {
+        edms = new ExternalDataManagementSystem();
+        edms.setCode("EDMS1");
+        edms.setUrlTemplate("http://www.$code$.ch");
+
         experiment =
                 new ExperimentBuilder().id(1).permID("e-1").identifier("/S/P/E1").type("my-type")
                         .property("a", "1").date(new Date(101)).modificationDate(new Date(102))
@@ -81,6 +90,10 @@ public class TranslatorTest extends AssertJUnit
                 new ContainerDataSetBuilder().code("ds-container").type("T3")
                         .experiment(experiment).sample(sample).contains(ds1.getDataSet())
                         .contains(ds2.getDataSet());
+        dsLink =
+                new LinkDataSetBuilder().code("lds").type("L1").experiment(experiment)
+                        .sample(sample).registrationDate(new Date(123456789L))
+                        .modificationDate(new Date(123459999L)).externalCode("EX_CODE").edms(edms);
     }
 
     @Test
@@ -135,7 +148,7 @@ public class TranslatorTest extends AssertJUnit
         DataSet translated =
                 Translator.translate(dsContainer.getContainerDataSet(),
                         EnumSet.noneOf(DataSet.Connections.class));
-        assertEquals(DataSetKind.CONTAINER.name(), translated.getDataSetKind());
+        assertTrue(translated.isContainerDataSet());
         assertBasicAttributes(ds1.getDataSet(), translated.getContainedDataSets().get(0));
         assertBasicAttributes(ds2.getDataSet(), translated.getContainedDataSets().get(1));
         assertChildrenNotRetrieved(translated);
@@ -209,8 +222,21 @@ public class TranslatorTest extends AssertJUnit
         assertEquals("[ds1]", translated.getParentCodes().toString());
     }
 
+    @Test
+    public void testTranslateLinkDataSet()
+    {
+        DataSet translated =
+                Translator.translate(dsLink.getLinkDataSet(),
+                        EnumSet.of(Connections.CHILDREN, Connections.PARENTS));
+
+        assertBasicAttributes(dsLink.getLinkDataSet(), translated);
+        assertTrue(translated.isLinkDataSet());
+        assertEquals(dsLink.getLinkDataSet().getExternalCode(), translated.getExternalDataSetCode());
+        assertEquals("http://www.EX_CODE.ch", translated.getExternalDataSetLink());
+    }
+
     private void assertBasicAttributes(
-            ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSet originalDataSet,
+            ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData originalDataSet,
             DataSet translatedDataSet)
     {
         assertEquals(originalDataSet.getCode(), translatedDataSet.getCode());
@@ -232,7 +258,8 @@ public class TranslatorTest extends AssertJUnit
                     translatedProperties.get(property.getPropertyType().getCode()));
         }
         assertEquals(originalProperties.size(), translatedProperties.size());
-        assertEquals(originalDataSet.getDataSetKind().name(), translatedDataSet.getDataSetKind());
+        assertEquals(originalDataSet.isContainer(), translatedDataSet.isContainerDataSet());
+        assertEquals(originalDataSet.isLinkData(), translatedDataSet.isLinkDataSet());
     }
 
     private void assertChildrenNotRetrieved(DataSet dataSet)
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/builders/LinkDataSetBuilder.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/builders/LinkDataSetBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b0a6f481c5ab72ec8fd19801dcdc8ec4fbb4d8b
--- /dev/null
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/builders/LinkDataSetBuilder.java
@@ -0,0 +1,63 @@
+/*
+ * 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.generic.shared.basic.dto.builders;
+
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSet;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalDataManagementSystem;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.LinkDataSet;
+
+/**
+ * Builder class for creating an instance of {@link DataSet} or {@link LinkDataSet}.
+ * 
+ * @author Pawel Glyzewski
+ */
+public class LinkDataSetBuilder extends AbstractDataSetBuilder<LinkDataSetBuilder>
+{
+    public LinkDataSetBuilder()
+    {
+        super(new LinkDataSet());
+    }
+
+    public LinkDataSetBuilder(long id)
+    {
+        this();
+        dataSet.setId(id);
+    }
+
+    public final LinkDataSet getLinkDataSet()
+    {
+        return dataSet.tryGetAsLinkDataSet();
+    }
+
+    public LinkDataSetBuilder externalCode(String code)
+    {
+        getLinkDataSet().setExternalCode(code);
+        return this;
+    }
+
+    public LinkDataSetBuilder edms(ExternalDataManagementSystem edms)
+    {
+        getLinkDataSet().setExternalDataManagementSystem(edms);
+        return this;
+    }
+
+    @Override
+    protected LinkDataSetBuilder asConcreteSubclass()
+    {
+        return this;
+    }
+}
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
index fc60c22098154469588bcaa505a1c673a4e89c25..e852c1d614ec3689331d17d38842755892934a29 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/api/v1/GeneralInformationServiceTest.java
@@ -17,6 +17,7 @@
 package ch.systemsx.cisd.openbis.systemtest.api.v1;
 
 import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertTrue;
 import static org.testng.AssertJUnit.fail;
 
 import java.text.ParseException;
@@ -61,7 +62,6 @@ import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SearchCriteria.MatchCl
 import ch.systemsx.cisd.openbis.generic.shared.api.v1.dto.SpaceWithProjectsAndRoleAssignments;
 import ch.systemsx.cisd.openbis.generic.shared.basic.IIdentifierHolder;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
-import ch.systemsx.cisd.openbis.generic.shared.basic.dto.DataSetKind;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.ExternalData;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataSetUpdatesDTO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.identifier.ExperimentIdentifierFactory;
@@ -621,7 +621,7 @@ public class GeneralInformationServiceTest extends SystemTestCase
         Collections.sort(childrenCodes);
         assertEquals("[20081105092259900-0, 20081105092259900-1]", childrenCodes.toString());
         DataSet dataSet = dataSets.get(9);
-        assertEquals(DataSetKind.CONTAINER.name(), dataSet.getDataSetKind());
+        assertTrue(dataSet.isContainerDataSet());
         assertEquals("[DataSet[20110509092359990-11,/CISD/DEFAULT/EXP-REUSE,<null>,HCS_IMAGE,"
                 + "{COMMENT=non-virtual comment},[]], "
                 + "DataSet[20110509092359990-12,/CISD/DEFAULT/EXP-REUSE,<null>,HCS_IMAGE,"
diff --git a/openbis/sourceTest/sql/postgresql/113/031=external_data_management_systems.tsv b/openbis/sourceTest/sql/postgresql/113/031=external_data_management_systems.tsv
index e8bb71c4e71264bc52154bac89b1862900effdce..ef7e1385a547e552e567d55b6e920c271dfe6274 100644
--- a/openbis/sourceTest/sql/postgresql/113/031=external_data_management_systems.tsv
+++ b/openbis/sourceTest/sql/postgresql/113/031=external_data_management_systems.tsv
@@ -1,2 +1,2 @@
-1	1	DMS_1	Test EDMS	http://example.edms.pl/code=${code}	f
-2	1	DMS_2	Test External openBIS instance	http://www.openbis.ch/perm_id=${code}	t
+1	1	DMS_1	Test EDMS	http://example.edms.pl/code=$code$	f
+2	1	DMS_2	Test External openBIS instance	http://www.openbis.ch/perm_id=$code$	t
diff --git a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/DataSet.java b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/DataSet.java
index aa3a5ae280d24634cd7c22ae198a14a4036f7b7e..b4051badc50c096d95de5da342e4e8d9e7db5038 100644
--- a/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/DataSet.java
+++ b/openbis_api/source/java/ch/systemsx/cisd/openbis/generic/shared/api/v1/dto/DataSet.java
@@ -67,7 +67,13 @@ public final class DataSet implements Serializable
 
         private String dataSetTypeCode;
 
-        private String dataSetKind;
+        private boolean containerDataSet;
+
+        private boolean linkDataSet;
+
+        private String externalDataSetCode;
+
+        private String externalDataSetLink;
 
         private EnumSet<Connections> retrievedConnections = EnumSet.noneOf(Connections.class);
 
@@ -173,14 +179,14 @@ public final class DataSet implements Serializable
             return registrationDetails;
         }
 
-        public String getDataSetKind()
+        public boolean isContainerDataSet()
         {
-            return dataSetKind;
+            return containerDataSet;
         }
 
-        public void setDataSetKind(String dataSetKind)
+        public void setContainerDataSet(boolean containerDataSet)
         {
-            this.dataSetKind = dataSetKind;
+            this.containerDataSet = containerDataSet;
         }
 
         public List<DataSet> getContainedDataSets()
@@ -194,6 +200,35 @@ public final class DataSet implements Serializable
                     (null == containedDataSets) ? new ArrayList<DataSet>() : containedDataSets;
         }
 
+        public boolean isLinkDataSet()
+        {
+            return linkDataSet;
+        }
+
+        public void setLinkDataSet(boolean linkDataSet)
+        {
+            this.linkDataSet = linkDataSet;
+        }
+
+        public String getExternalDataSetCode()
+        {
+            return externalDataSetCode;
+        }
+
+        public void setExternalDataSetCode(String externalDataSetCode)
+        {
+            this.externalDataSetCode = externalDataSetCode;
+        }
+
+        public String getExternalDataSetLink()
+        {
+            return externalDataSetLink;
+        }
+
+        public void setExternalDataSetLink(String externalDataSetLink)
+        {
+            this.externalDataSetLink = externalDataSetLink;
+        }
     }
 
     private String code;
@@ -204,7 +239,13 @@ public final class DataSet implements Serializable
 
     private String dataSetTypeCode;
 
-    private String dataSetKind;
+    private boolean containerDataSet;
+
+    private boolean linkDataSet;
+
+    private String externalDataSetCode;
+
+    private String externalDataSetLink;
 
     private HashMap<String, String> properties;
 
@@ -248,8 +289,11 @@ public final class DataSet implements Serializable
         InitializingChecks.checkValidRegistrationDetails(initializer.getRegistrationDetails(),
                 "Unspecified entity registration details.");
         this.registrationDetails = initializer.getRegistrationDetails();
-        this.dataSetKind = initializer.getDataSetKind();
+        this.containerDataSet = initializer.isContainerDataSet();
         this.containedDataSets = initializer.getContainedDataSets();
+        this.linkDataSet = initializer.isLinkDataSet();
+        this.externalDataSetCode = initializer.getExternalDataSetCode();
+        this.externalDataSetLink = initializer.getExternalDataSetLink();
 
     }
 
@@ -353,9 +397,24 @@ public final class DataSet implements Serializable
         return registrationDetails;
     }
 
-    public String getDataSetKind()
+    public boolean isContainerDataSet()
+    {
+        return containerDataSet;
+    }
+
+    public boolean isLinkDataSet()
+    {
+        return linkDataSet;
+    }
+
+    public String getExternalDataSetCode()
+    {
+        return externalDataSetCode;
+    }
+
+    public String getExternalDataSetLink()
     {
-        return dataSetKind;
+        return externalDataSetLink;
     }
 
     public List<DataSet> getContainedDataSets()
@@ -456,12 +515,27 @@ public final class DataSet implements Serializable
         this.registrationDetails = registrationDetails;
     }
 
-    public void setDataSetKind(String dataSetKind)
+    private void setContainerDataSet(boolean containerDataSet)
+    {
+        this.containerDataSet = containerDataSet;
+    }
+
+    private void setLinkDataSet(boolean linkDataSet)
+    {
+        this.linkDataSet = linkDataSet;
+    }
+
+    private void setExternalDataSetCode(String externalDataSetCode)
+    {
+        this.externalDataSetCode = externalDataSetCode;
+    }
+
+    private void setExternalDataSetLink(String externalDataSetLink)
     {
-        this.dataSetKind = dataSetKind;
+        this.externalDataSetLink = externalDataSetLink;
     }
 
-    public void setContainedDataSets(List<DataSet> containedDataSets)
+    private void setContainedDataSets(List<DataSet> containedDataSets)
     {
         this.containedDataSets = containedDataSets;
     }