From 6c73e7fc6066ec353db174d551c7931de0708874 Mon Sep 17 00:00:00 2001
From: pkupczyk <pkupczyk>
Date: Fri, 15 Apr 2016 14:57:09 +0000
Subject: [PATCH] SSDM-3476 : V3 AS API - tags - createTags (not finished yet)

SVN: 36191
---
 .../common/IReindexObjectExecutor.java        |  32 +++
 .../common/ReindexObjectExecutor.java         |  62 +++++
 .../dataset/ISetDataSetChildrenExecutor.java  |   8 +-
 .../ISetDataSetComponentsExecutor.java        |   8 +-
 .../dataset/ISetDataSetContainerExecutor.java |   8 +-
 .../dataset/ISetDataSetParentsExecutor.java   |   8 +-
 .../dataset/SetDataSetChildrenExecutor.java   |   2 +-
 .../dataset/SetDataSetComponentsExecutor.java |   2 +-
 .../dataset/SetDataSetContainerExecutor.java  |   2 +-
 .../dataset/SetDataSetParentsExecutor.java    |   2 +-
 .../SetDataSetRelatedDataSetsExecutor.java    |  11 +-
 ...actSetEntityMultipleRelationsExecutor.java |  58 ++---
 ...stractSetEntityToManyRelationExecutor.java |  14 +-
 .../ISetEntityRelationsWithCacheExecutor.java |  31 +++
 .../sample/ISetSampleChildrenExecutor.java    |   8 +-
 .../sample/ISetSampleComponentsExecutor.java  |   8 +-
 .../sample/ISetSampleParentsExecutor.java     |   8 +-
 .../sample/SetSampleChildrenExecutor.java     |   2 +-
 .../sample/SetSampleComponentsExecutor.java   |   2 +-
 .../sample/SetSampleParentsExecutor.java      |   2 +-
 .../SetSampleRelatedSamplesExecutor.java      |  11 +-
 .../v3/executor/tag/CreateTagExecutor.java    |  13 +-
 .../executor/tag/ISetTagDataSetsExecutor.java |  29 +++
 .../tag/ISetTagDataSetsWithCacheExecutor.java |  32 +++
 .../tag/ISetTagExperimentsExecutor.java       |  29 +++
 .../ISetTagExperimentsWithCacheExecutor.java  |  32 +++
 .../executor/tag/ISetTagSamplesExecutor.java  |  29 +++
 .../tag/ISetTagSamplesWithCacheExecutor.java  |  32 +++
 .../executor/tag/SetTagDataSetsExecutor.java  |  84 +++++++
 .../tag/SetTagDataSetsWithCacheExecutor.java  |  48 ++++
 .../tag/SetTagEntitiesWithCacheExecutor.java  |  69 ++++++
 .../tag/SetTagExperimentsExecutor.java        |  83 +++++++
 .../SetTagExperimentsWithCacheExecutor.java   |  48 ++++
 .../executor/tag/SetTagSamplesExecutor.java   |  83 +++++++
 .../tag/SetTagSamplesWithCacheExecutor.java   |  48 ++++
 .../UpdateTagDataSetsWithCacheExecutor.java   |   2 +-
 ...> UpdateTagEntitiesWithCacheExecutor.java} |  24 +-
 ...UpdateTagExperimentsWithCacheExecutor.java |   2 +-
 .../UpdateTagMaterialsWithCacheExecutor.java  |   2 +-
 .../UpdateTagSamplesWithCacheExecutor.java    |   2 +-
 .../api/v3/as/dto/tag/create/TagCreation.js   |  47 +++-
 .../systemtest/asapi/v3/CreateTagTest.java    | 227 ++++++++++++++++++
 .../asapi/v3/dto/tag/create/TagCreation.java  |  53 ++++
 .../generic/sharedapi/v3/dictionary.txt       |   6 +-
 44 files changed, 1201 insertions(+), 112 deletions(-)
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/IReindexObjectExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/ReindexObjectExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/ISetEntityRelationsWithCacheExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagDataSetsExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagDataSetsWithCacheExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagExperimentsExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagExperimentsWithCacheExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagSamplesExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagSamplesWithCacheExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagDataSetsExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagDataSetsWithCacheExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagEntitiesWithCacheExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagExperimentsExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagExperimentsWithCacheExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagSamplesExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagSamplesWithCacheExecutor.java
 rename openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/{UpdateTagEntitiesExecutor.java => UpdateTagEntitiesWithCacheExecutor.java} (77%)
 create mode 100644 openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/CreateTagTest.java

diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/IReindexObjectExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/IReindexObjectExecutor.java
new file mode 100644
index 00000000000..e79b86cb1b0
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/IReindexObjectExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.common;
+
+import java.util.Collection;
+
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
+
+/**
+ * @author pkupczyk
+ */
+public interface IReindexObjectExecutor
+{
+
+    <T extends IIdHolder> void reindex(IOperationContext context, Class<T> objectClass, Collection<T> objects);
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/ReindexObjectExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/ReindexObjectExecutor.java
new file mode 100644
index 00000000000..dd331046109
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/common/ReindexObjectExecutor.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.common;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdateScheduler;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation;
+import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class ReindexObjectExecutor implements IReindexObjectExecutor
+{
+
+    @Autowired
+    private IDAOFactory daoFactory;
+
+    @Override
+    public <T extends IIdHolder> void reindex(IOperationContext context, Class<T> objectClass, Collection<T> objects)
+    {
+        IFullTextIndexUpdateScheduler indexUpdater = daoFactory.getPersistencyResources().getIndexUpdateScheduler();
+        List<Long> objectIds = new ArrayList<Long>();
+
+        for (IIdHolder object : objects)
+        {
+            if (object != null && object.getId() != null)
+            {
+                objectIds.add(object.getId());
+            }
+        }
+
+        if (false == objectIds.isEmpty())
+        {
+            indexUpdater.scheduleUpdate(IndexUpdateOperation.reindex(objectClass, objectIds));
+        }
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetChildrenExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetChildrenExecutor.java
index ddab7ce4892..1c2b8a7edc3 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetChildrenExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetChildrenExecutor.java
@@ -16,19 +16,15 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset;
 
-import java.util.Map;
-
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 
 /**
  * @author pkupczyk
  */
-public interface ISetDataSetChildrenExecutor
+public interface ISetDataSetChildrenExecutor extends ISetEntityRelationsWithCacheExecutor<DataSetCreation, DataPE, IDataSetId, DataPE>
 {
 
-    void set(IOperationContext context, Map<DataSetCreation, DataPE> creationsMap, Map<IDataSetId, DataPE> relatedMap);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetComponentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetComponentsExecutor.java
index 21b3b6623f9..51cbde173ff 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetComponentsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetComponentsExecutor.java
@@ -16,19 +16,15 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset;
 
-import java.util.Map;
-
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 
 /**
  * @author pkupczyk
  */
-public interface ISetDataSetComponentsExecutor
+public interface ISetDataSetComponentsExecutor extends ISetEntityRelationsWithCacheExecutor<DataSetCreation, DataPE, IDataSetId, DataPE>
 {
 
-    void set(IOperationContext context, Map<DataSetCreation, DataPE> creationsMap, Map<IDataSetId, DataPE> relatedMap);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetContainerExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetContainerExecutor.java
index 39ff7136927..2a74231d082 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetContainerExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetContainerExecutor.java
@@ -16,19 +16,15 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset;
 
-import java.util.Map;
-
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 
 /**
  * @author pkupczyk
  */
-public interface ISetDataSetContainerExecutor
+public interface ISetDataSetContainerExecutor extends ISetEntityRelationsWithCacheExecutor<DataSetCreation, DataPE, IDataSetId, DataPE>
 {
 
-    void set(IOperationContext context, Map<DataSetCreation, DataPE> creationsMap, Map<IDataSetId, DataPE> relatedMap);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetParentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetParentsExecutor.java
index c1422d3cba8..579a2dcdf31 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetParentsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/ISetDataSetParentsExecutor.java
@@ -16,19 +16,15 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset;
 
-import java.util.Map;
-
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.create.DataSetCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
 
 /**
  * @author pkupczyk
  */
-public interface ISetDataSetParentsExecutor
+public interface ISetDataSetParentsExecutor extends ISetEntityRelationsWithCacheExecutor<DataSetCreation, DataPE, IDataSetId, DataPE>
 {
 
-    void set(IOperationContext context, Map<DataSetCreation, DataPE> creationsMap, Map<IDataSetId, DataPE> relatedMap);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetChildrenExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetChildrenExecutor.java
index ae5ca3121bc..bb0753745cc 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetChildrenExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetChildrenExecutor.java
@@ -31,7 +31,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
  * @author pkupczyk
  */
 @Component
-public class SetDataSetChildrenExecutor extends AbstractSetEntityToManyRelationExecutor<DataSetCreation, DataPE, IDataSetId> implements
+public class SetDataSetChildrenExecutor extends AbstractSetEntityToManyRelationExecutor<DataSetCreation, DataPE, IDataSetId, DataPE> implements
         ISetDataSetChildrenExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetComponentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetComponentsExecutor.java
index 846d08ecc4f..4bf2e385e08 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetComponentsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetComponentsExecutor.java
@@ -32,7 +32,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
  * @author pkupczyk
  */
 @Component
-public class SetDataSetComponentsExecutor extends AbstractSetEntityToManyRelationExecutor<DataSetCreation, DataPE, IDataSetId> implements
+public class SetDataSetComponentsExecutor extends AbstractSetEntityToManyRelationExecutor<DataSetCreation, DataPE, IDataSetId, DataPE> implements
         ISetDataSetComponentsExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetContainerExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetContainerExecutor.java
index 48a16e6c72f..343f817bf9b 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetContainerExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetContainerExecutor.java
@@ -32,7 +32,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
  * @author pkupczyk
  */
 @Component
-public class SetDataSetContainerExecutor extends AbstractSetEntityToManyRelationExecutor<DataSetCreation, DataPE, IDataSetId> implements
+public class SetDataSetContainerExecutor extends AbstractSetEntityToManyRelationExecutor<DataSetCreation, DataPE, IDataSetId, DataPE> implements
         ISetDataSetContainerExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetParentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetParentsExecutor.java
index 067270a908d..721d3c0fdc0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetParentsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetParentsExecutor.java
@@ -31,7 +31,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
  * @author pkupczyk
  */
 @Component
-public class SetDataSetParentsExecutor extends AbstractSetEntityToManyRelationExecutor<DataSetCreation, DataPE, IDataSetId> implements
+public class SetDataSetParentsExecutor extends AbstractSetEntityToManyRelationExecutor<DataSetCreation, DataPE, IDataSetId, DataPE> implements
         ISetDataSetParentsExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetRelatedDataSetsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetRelatedDataSetsExecutor.java
index 01677bc512f..6f4d75d052d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetRelatedDataSetsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/dataset/SetDataSetRelatedDataSetsExecutor.java
@@ -35,7 +35,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
  * @author pkupczyk
  */
 @Component
-public class SetDataSetRelatedDataSetsExecutor extends AbstractSetEntityMultipleRelationsExecutor<DataSetCreation, DataPE, IDataSetId> implements
+public class SetDataSetRelatedDataSetsExecutor extends AbstractSetEntityMultipleRelationsExecutor<DataSetCreation, DataPE, IDataSetId, DataPE>
+        implements
         ISetDataSetRelatedDataSetsExecutor
 {
 
@@ -55,7 +56,7 @@ public class SetDataSetRelatedDataSetsExecutor extends AbstractSetEntityMultiple
     private ISetDataSetChildrenExecutor setDataSetChildrenExecutor;
 
     @Override
-    protected void addRelatedIds(Set<IDataSetId> relatedIds, DataSetCreation creation)
+    protected void addRelatedIds(Set<IDataSetId> relatedIds, DataSetCreation creation, DataPE entity)
     {
         addRelatedIds(relatedIds, creation.getContainerIds());
         addRelatedIds(relatedIds, creation.getComponentIds());
@@ -63,6 +64,12 @@ public class SetDataSetRelatedDataSetsExecutor extends AbstractSetEntityMultiple
         addRelatedIds(relatedIds, creation.getChildIds());
     }
 
+    @Override
+    protected void addRelated(Map<IDataSetId, DataPE> relatedMap, DataSetCreation creation, DataPE entity)
+    {
+        addRelated(relatedMap, creation.getCreationId(), entity);
+    }
+
     @Override
     protected Map<IDataSetId, DataPE> map(IOperationContext context, List<IDataSetId> relatedIds)
     {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractSetEntityMultipleRelationsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractSetEntityMultipleRelationsExecutor.java
index ea126e9822e..64c9b638647 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractSetEntityMultipleRelationsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractSetEntityMultipleRelationsExecutor.java
@@ -29,7 +29,6 @@ import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.CreationId;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.IObjectId;
-import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.interfaces.ICreationIdHolder;
 import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.ObjectNotFoundException;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.context.Progress;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
@@ -38,45 +37,41 @@ import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
  * @author pkupczyk
  */
 @Component
-public abstract class AbstractSetEntityMultipleRelationsExecutor<ENTITY_CREATION extends ICreationIdHolder, ENTITY_PE, ENTITY_ID extends IObjectId>
+public abstract class AbstractSetEntityMultipleRelationsExecutor<ENTITY_CREATION, ENTITY_PE, RELATED_ID extends IObjectId, RELATED_PE>
         implements ISetEntityRelationsExecutor<ENTITY_CREATION, ENTITY_PE>
 {
 
-    @SuppressWarnings("unchecked")
     @Override
     public void set(IOperationContext context, Map<ENTITY_CREATION, ENTITY_PE> creationsMap)
     {
-        Map<IObjectId, ENTITY_PE> relatedMap = getRelatedMap(context, creationsMap);
+        Map<RELATED_ID, RELATED_PE> relatedMap = getRelatedMap(context, creationsMap);
 
-        set(context, creationsMap, (Map<ENTITY_ID, ENTITY_PE>) relatedMap);
+        set(context, creationsMap, relatedMap);
     }
 
-    private Map<IObjectId, ENTITY_PE> getRelatedMap(IOperationContext context, Map<ENTITY_CREATION, ENTITY_PE> creationsMap)
+    private Map<RELATED_ID, RELATED_PE> getRelatedMap(IOperationContext context, Map<ENTITY_CREATION, ENTITY_PE> creationsMap)
     {
         context.pushProgress(new Progress("load related entities"));
 
-        Set<ENTITY_ID> relatedIds = new HashSet<ENTITY_ID>();
-        for (ENTITY_CREATION creation : creationsMap.keySet())
+        Set<RELATED_ID> relatedIds = new HashSet<RELATED_ID>();
+        for (Entry<ENTITY_CREATION, ENTITY_PE> entry : creationsMap.entrySet())
         {
-            addRelatedIds(relatedIds, creation);
+            addRelatedIds(relatedIds, entry.getKey(), entry.getValue());
         }
 
-        Map<IObjectId, ENTITY_PE> relatedMap = new HashMap<IObjectId, ENTITY_PE>();
+        Map<RELATED_ID, RELATED_PE> relatedMap = new HashMap<RELATED_ID, RELATED_PE>();
 
         for (Entry<ENTITY_CREATION, ENTITY_PE> entry : creationsMap.entrySet())
         {
             ENTITY_CREATION creation = entry.getKey();
             ENTITY_PE entity = entry.getValue();
 
-            if (creation.getCreationId() != null)
-            {
-                relatedMap.put(creation.getCreationId(), entity);
-            }
+            addRelated(relatedMap, creation, entity);
         }
 
-        List<ENTITY_ID> toLoadIds = new LinkedList<ENTITY_ID>();
+        List<RELATED_ID> toLoadIds = new LinkedList<RELATED_ID>();
 
-        for (ENTITY_ID relatedId : relatedIds)
+        for (RELATED_ID relatedId : relatedIds)
         {
             if (relatedId instanceof CreationId)
             {
@@ -84,19 +79,18 @@ public abstract class AbstractSetEntityMultipleRelationsExecutor<ENTITY_CREATION
                 {
                     throw new ObjectNotFoundException(relatedId);
                 }
-            }
-            else
+            } else
             {
                 toLoadIds.add(relatedId);
             }
         }
 
-        Map<ENTITY_ID, ENTITY_PE> loadedMap = map(context, toLoadIds);
+        Map<RELATED_ID, RELATED_PE> loadedMap = map(context, toLoadIds);
         relatedMap.putAll(loadedMap);
 
-        for (ENTITY_ID relatedId : relatedIds)
+        for (RELATED_ID relatedId : relatedIds)
         {
-            ENTITY_PE related = relatedMap.get(relatedId);
+            RELATED_PE related = relatedMap.get(relatedId);
 
             if (related == null)
             {
@@ -111,7 +105,7 @@ public abstract class AbstractSetEntityMultipleRelationsExecutor<ENTITY_CREATION
         return relatedMap;
     }
 
-    protected void addRelatedIds(Set<ENTITY_ID> relatedIds, Collection<? extends ENTITY_ID> relatedIdsToAdd)
+    protected void addRelatedIds(Set<RELATED_ID> relatedIds, Collection<? extends RELATED_ID> relatedIdsToAdd)
     {
         if (relatedIdsToAdd != null)
         {
@@ -119,7 +113,7 @@ public abstract class AbstractSetEntityMultipleRelationsExecutor<ENTITY_CREATION
         }
     }
 
-    protected void addRelatedIds(Set<ENTITY_ID> relatedIds, ENTITY_ID relatedIdToAdd)
+    protected void addRelatedIds(Set<RELATED_ID> relatedIds, RELATED_ID relatedIdToAdd)
     {
         if (relatedIdToAdd != null)
         {
@@ -127,12 +121,22 @@ public abstract class AbstractSetEntityMultipleRelationsExecutor<ENTITY_CREATION
         }
     }
 
-    protected abstract void addRelatedIds(Set<ENTITY_ID> relatedIds, ENTITY_CREATION creation);
+    protected void addRelated(Map<RELATED_ID, RELATED_PE> relatedMap, RELATED_ID relatedId, RELATED_PE related)
+    {
+        if (relatedId != null && related != null)
+        {
+            relatedMap.put(relatedId, related);
+        }
+    }
+
+    protected abstract void addRelatedIds(Set<RELATED_ID> relatedIds, ENTITY_CREATION creation, ENTITY_PE entity);
+
+    protected abstract void addRelated(Map<RELATED_ID, RELATED_PE> relatedMap, ENTITY_CREATION creation, ENTITY_PE entity);
 
-    protected abstract Map<ENTITY_ID, ENTITY_PE> map(IOperationContext context, List<ENTITY_ID> relatedIds);
+    protected abstract Map<RELATED_ID, RELATED_PE> map(IOperationContext context, List<RELATED_ID> relatedIds);
 
-    protected abstract void check(IOperationContext context, ENTITY_ID relatedId, ENTITY_PE related);
+    protected abstract void check(IOperationContext context, RELATED_ID relatedId, RELATED_PE related);
 
-    protected abstract void set(IOperationContext context, Map<ENTITY_CREATION, ENTITY_PE> creationsMap, Map<ENTITY_ID, ENTITY_PE> relatedMap);
+    protected abstract void set(IOperationContext context, Map<ENTITY_CREATION, ENTITY_PE> creationsMap, Map<RELATED_ID, RELATED_PE> relatedMap);
 
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractSetEntityToManyRelationExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractSetEntityToManyRelationExecutor.java
index f59f5387973..b371df0399d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractSetEntityToManyRelationExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/AbstractSetEntityToManyRelationExecutor.java
@@ -29,24 +29,24 @@ import ch.systemsx.cisd.openbis.generic.server.business.IRelationshipService;
 /**
  * @author pkupczyk
  */
-public abstract class AbstractSetEntityToManyRelationExecutor<ENTITY_CREATION, ENTITY_PE, ENTITY_ID>
+public abstract class AbstractSetEntityToManyRelationExecutor<ENTITY_CREATION, ENTITY_PE, RELATED_ID, RELATED_PE>
 {
 
     @Resource(name = ComponentNames.RELATIONSHIP_SERVICE)
     protected IRelationshipService relationshipService;
 
-    public void set(IOperationContext context, Map<ENTITY_CREATION, ENTITY_PE> creationsMap, Map<ENTITY_ID, ENTITY_PE> relatedMap)
+    public void set(IOperationContext context, Map<ENTITY_CREATION, ENTITY_PE> creationsMap, Map<RELATED_ID, RELATED_PE> relatedMap)
     {
         for (ENTITY_CREATION creation : creationsMap.keySet())
         {
             ENTITY_PE entity = creationsMap.get(creation);
-            Collection<? extends ENTITY_ID> relatedIds = getRelatedIds(context, creation);
+            Collection<? extends RELATED_ID> relatedIds = getRelatedIds(context, creation);
 
             if (relatedIds != null)
             {
-                Collection<ENTITY_PE> related = new LinkedList<ENTITY_PE>();
+                Collection<RELATED_PE> related = new LinkedList<RELATED_PE>();
 
-                for (ENTITY_ID relatedId : relatedIds)
+                for (RELATED_ID relatedId : relatedIds)
                 {
                     related.add(relatedMap.get(relatedId));
                 }
@@ -59,8 +59,8 @@ public abstract class AbstractSetEntityToManyRelationExecutor<ENTITY_CREATION, E
         }
     }
 
-    protected abstract Collection<? extends ENTITY_ID> getRelatedIds(IOperationContext context, ENTITY_CREATION creation);
+    protected abstract Collection<? extends RELATED_ID> getRelatedIds(IOperationContext context, ENTITY_CREATION creation);
 
-    protected abstract void setRelated(IOperationContext context, ENTITY_PE entity, Collection<ENTITY_PE> related);
+    protected abstract void setRelated(IOperationContext context, ENTITY_PE entity, Collection<RELATED_PE> related);
 
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/ISetEntityRelationsWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/ISetEntityRelationsWithCacheExecutor.java
new file mode 100644
index 00000000000..9eeb0032010
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/entity/ISetEntityRelationsWithCacheExecutor.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 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.ethz.sis.openbis.generic.server.asapi.v3.executor.entity;
+
+import java.util.Map;
+
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISetEntityRelationsWithCacheExecutor<ENTITY_CREATION, ENTITY_PE, RELATED_ID, RELATED_PE>
+{
+
+    public void set(IOperationContext context, Map<ENTITY_CREATION, ENTITY_PE> entitiesMap, Map<RELATED_ID, RELATED_PE> relatedMap);
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleChildrenExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleChildrenExecutor.java
index fcbd85a1176..6a68945efed 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleChildrenExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleChildrenExecutor.java
@@ -16,19 +16,15 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.sample;
 
-import java.util.Map;
-
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.create.SampleCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 
 /**
  * @author pkupczyk
  */
-public interface ISetSampleChildrenExecutor
+public interface ISetSampleChildrenExecutor extends ISetEntityRelationsWithCacheExecutor<SampleCreation, SamplePE, ISampleId, SamplePE>
 {
 
-    public void set(IOperationContext context, Map<SampleCreation, SamplePE> creationsMap, Map<ISampleId, SamplePE> sampleMap);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleComponentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleComponentsExecutor.java
index aeee846d986..84a4f05e2db 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleComponentsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleComponentsExecutor.java
@@ -16,19 +16,15 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.sample;
 
-import java.util.Map;
-
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.create.SampleCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 
 /**
  * @author pkupczyk
  */
-public interface ISetSampleComponentsExecutor
+public interface ISetSampleComponentsExecutor extends ISetEntityRelationsWithCacheExecutor<SampleCreation, SamplePE, ISampleId, SamplePE>
 {
 
-    public void set(IOperationContext context, Map<SampleCreation, SamplePE> creationsMap, Map<ISampleId, SamplePE> sampleMap);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleParentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleParentsExecutor.java
index 00976bb2214..af14dfd15d1 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleParentsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/ISetSampleParentsExecutor.java
@@ -16,19 +16,15 @@
 
 package ch.ethz.sis.openbis.generic.server.asapi.v3.executor.sample;
 
-import java.util.Map;
-
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.create.SampleCreation;
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
-import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
 import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
 
 /**
  * @author pkupczyk
  */
-public interface ISetSampleParentsExecutor
+public interface ISetSampleParentsExecutor extends ISetEntityRelationsWithCacheExecutor<SampleCreation, SamplePE, ISampleId, SamplePE>
 {
 
-    public void set(IOperationContext context, Map<SampleCreation, SamplePE> creationsMap, Map<ISampleId, SamplePE> sampleMap);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleChildrenExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleChildrenExecutor.java
index 8d65646b289..df144c9fb13 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleChildrenExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleChildrenExecutor.java
@@ -33,7 +33,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
  * @author pkupczyk
  */
 @Component
-public class SetSampleChildrenExecutor extends AbstractSetEntityToManyRelationExecutor<SampleCreation, SamplePE, ISampleId> implements
+public class SetSampleChildrenExecutor extends AbstractSetEntityToManyRelationExecutor<SampleCreation, SamplePE, ISampleId, SamplePE> implements
         ISetSampleChildrenExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleComponentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleComponentsExecutor.java
index 90cb2766aae..ef810d2202d 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleComponentsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleComponentsExecutor.java
@@ -31,7 +31,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
  * @author pkupczyk
  */
 @Component
-public class SetSampleComponentsExecutor extends AbstractSetEntityToManyRelationExecutor<SampleCreation, SamplePE, ISampleId> implements
+public class SetSampleComponentsExecutor extends AbstractSetEntityToManyRelationExecutor<SampleCreation, SamplePE, ISampleId, SamplePE> implements
         ISetSampleComponentsExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleParentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleParentsExecutor.java
index a05936e5c65..1a656f9d3e6 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleParentsExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleParentsExecutor.java
@@ -33,7 +33,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
  * @author pkupczyk
  */
 @Component
-public class SetSampleParentsExecutor extends AbstractSetEntityToManyRelationExecutor<SampleCreation, SamplePE, ISampleId> implements
+public class SetSampleParentsExecutor extends AbstractSetEntityToManyRelationExecutor<SampleCreation, SamplePE, ISampleId, SamplePE> implements
         ISetSampleParentsExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleRelatedSamplesExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleRelatedSamplesExecutor.java
index dcf2f735240..3462a9e3816 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleRelatedSamplesExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/sample/SetSampleRelatedSamplesExecutor.java
@@ -35,7 +35,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
  * @author pkupczyk
  */
 @Component
-public class SetSampleRelatedSamplesExecutor extends AbstractSetEntityMultipleRelationsExecutor<SampleCreation, SamplePE, ISampleId> implements
+public class SetSampleRelatedSamplesExecutor extends AbstractSetEntityMultipleRelationsExecutor<SampleCreation, SamplePE, ISampleId, SamplePE>
+        implements
         ISetSampleRelatedSamplesExecutor
 {
 
@@ -55,7 +56,7 @@ public class SetSampleRelatedSamplesExecutor extends AbstractSetEntityMultipleRe
     private ISetSampleChildrenExecutor setSampleChildrenExecutor;
 
     @Override
-    protected void addRelatedIds(Set<ISampleId> relatedIds, SampleCreation creation)
+    protected void addRelatedIds(Set<ISampleId> relatedIds, SampleCreation creation, SamplePE entity)
     {
         addRelatedIds(relatedIds, creation.getContainerId());
         addRelatedIds(relatedIds, creation.getComponentIds());
@@ -63,6 +64,12 @@ public class SetSampleRelatedSamplesExecutor extends AbstractSetEntityMultipleRe
         addRelatedIds(relatedIds, creation.getChildIds());
     }
 
+    @Override
+    protected void addRelated(Map<ISampleId, SamplePE> relatedMap, SampleCreation creation, SamplePE entity)
+    {
+        addRelated(relatedMap, creation.getCreationId(), entity);
+    }
+
     @Override
     protected Map<ISampleId, SamplePE> map(IOperationContext context, List<ISampleId> relatedIds)
     {
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/CreateTagExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/CreateTagExecutor.java
index e0d290fe0c9..5d474142fd6 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/CreateTagExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/CreateTagExecutor.java
@@ -46,6 +46,15 @@ public class CreateTagExecutor extends AbstractCreateEntityExecutor<TagCreation,
     @Autowired
     private IDAOFactory daoFactory;
 
+    @Autowired
+    private ISetTagExperimentsExecutor setTagExperimentsExecutor;
+
+    @Autowired
+    private ISetTagSamplesExecutor setTagSamplesExecutor;
+
+    @Autowired
+    private ISetTagDataSetsExecutor setTagDataSetsExecutor;
+
     @Override
     protected List<MetaprojectPE> createEntities(IOperationContext context, Collection<TagCreation> creations)
     {
@@ -100,7 +109,9 @@ public class CreateTagExecutor extends AbstractCreateEntityExecutor<TagCreation,
     @Override
     protected void updateAll(IOperationContext context, Map<TagCreation, MetaprojectPE> entitiesMap)
     {
-        // nothing to do
+        setTagExperimentsExecutor.set(context, entitiesMap);
+        setTagSamplesExecutor.set(context, entitiesMap);
+        setTagDataSetsExecutor.set(context, entitiesMap);
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagDataSetsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagDataSetsExecutor.java
new file mode 100644
index 00000000000..85d63b71a38
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagDataSetsExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsExecutor;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISetTagDataSetsExecutor extends ISetEntityRelationsExecutor<TagCreation, MetaprojectPE>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagDataSetsWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagDataSetsWithCacheExecutor.java
new file mode 100644
index 00000000000..96d0e371d9f
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagDataSetsWithCacheExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISetTagDataSetsWithCacheExecutor
+        extends ISetEntityRelationsWithCacheExecutor<TagCreation, MetaprojectPE, IDataSetId, DataPE>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagExperimentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagExperimentsExecutor.java
new file mode 100644
index 00000000000..c9def06cbef
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagExperimentsExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsExecutor;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISetTagExperimentsExecutor extends ISetEntityRelationsExecutor<TagCreation, MetaprojectPE>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagExperimentsWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagExperimentsWithCacheExecutor.java
new file mode 100644
index 00000000000..847662e9226
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagExperimentsWithCacheExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISetTagExperimentsWithCacheExecutor
+        extends ISetEntityRelationsWithCacheExecutor<TagCreation, MetaprojectPE, IExperimentId, ExperimentPE>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagSamplesExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagSamplesExecutor.java
new file mode 100644
index 00000000000..4885b4a0e84
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagSamplesExecutor.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsExecutor;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISetTagSamplesExecutor extends ISetEntityRelationsExecutor<TagCreation, MetaprojectPE>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagSamplesWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagSamplesWithCacheExecutor.java
new file mode 100644
index 00000000000..a5459df9f85
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/ISetTagSamplesWithCacheExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.ISetEntityRelationsWithCacheExecutor;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+
+/**
+ * @author pkupczyk
+ */
+public interface ISetTagSamplesWithCacheExecutor
+        extends ISetEntityRelationsWithCacheExecutor<TagCreation, MetaprojectPE, ISampleId, SamplePE>
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagDataSetsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagDataSetsExecutor.java
new file mode 100644
index 00000000000..8ad7961affd
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagDataSetsExecutor.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.UnauthorizedObjectAccessException;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.dataset.IMapDataSetByIdExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.AbstractSetEntityMultipleRelationsExecutor;
+import ch.systemsx.cisd.openbis.generic.server.authorization.validator.DataSetPEByExperimentOrSampleIdentifierValidator;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class SetTagDataSetsExecutor extends AbstractSetEntityMultipleRelationsExecutor<TagCreation, MetaprojectPE, IDataSetId, DataPE>
+        implements ISetTagDataSetsExecutor
+{
+
+    @Autowired
+    private IMapDataSetByIdExecutor mapDataSetExecutor;
+
+    @Autowired
+    private ISetTagDataSetsWithCacheExecutor setTagDataSetsWithCacheExecutor;
+
+    @Override
+    protected void addRelatedIds(Set<IDataSetId> relatedIds, TagCreation creation, MetaprojectPE entity)
+    {
+        addRelatedIds(relatedIds, creation.getDataSetIds());
+    }
+
+    @Override
+    protected void addRelated(Map<IDataSetId, DataPE> relatedMap, TagCreation creation, MetaprojectPE entity)
+    {
+        // nothing to do here
+    }
+
+    @Override
+    protected Map<IDataSetId, DataPE> map(IOperationContext context, List<IDataSetId> relatedIds)
+    {
+        return mapDataSetExecutor.map(context, relatedIds);
+    }
+
+    @Override
+    protected void check(IOperationContext context, IDataSetId relatedId, DataPE related)
+    {
+        if (false == new DataSetPEByExperimentOrSampleIdentifierValidator().doValidation(context.getSession().tryGetPerson(), related))
+        {
+            throw new UnauthorizedObjectAccessException(relatedId);
+        }
+
+    }
+
+    @Override
+    protected void set(IOperationContext context, Map<TagCreation, MetaprojectPE> creationsMap, Map<IDataSetId, DataPE> relatedMap)
+    {
+        setTagDataSetsWithCacheExecutor.set(context, creationsMap, relatedMap);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagDataSetsWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagDataSetsWithCacheExecutor.java
new file mode 100644
index 00000000000..1a431e556f3
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagDataSetsWithCacheExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import java.util.Collection;
+
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class SetTagDataSetsWithCacheExecutor extends SetTagEntitiesWithCacheExecutor<IDataSetId, DataPE>
+        implements ISetTagDataSetsWithCacheExecutor
+{
+
+    @Override
+    protected Class<DataPE> getRelatedClass()
+    {
+        return DataPE.class;
+    }
+
+    @Override
+    protected Collection<? extends IDataSetId> getRelatedIds(IOperationContext context, TagCreation creation)
+    {
+        return creation.getDataSetIds();
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagEntitiesWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagEntitiesWithCacheExecutor.java
new file mode 100644
index 00000000000..8c05dfef99f
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagEntitiesWithCacheExecutor.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.common.id.IObjectId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.IReindexObjectExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.AbstractSetEntityToManyRelationExecutor;
+import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityWithMetaprojects;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public abstract class SetTagEntitiesWithCacheExecutor<RELATED_ID extends IObjectId, RELATED_PE extends IEntityWithMetaprojects>
+        extends AbstractSetEntityToManyRelationExecutor<TagCreation, MetaprojectPE, RELATED_ID, RELATED_PE>
+{
+
+    @Autowired
+    private IDAOFactory daoFactory;
+
+    @Autowired
+    private IReindexObjectExecutor reindexObjectExecutor;
+
+    protected abstract Class<RELATED_PE> getRelatedClass();
+
+    @Override
+    public void set(IOperationContext context, Map<TagCreation, MetaprojectPE> creationsMap, Map<RELATED_ID, RELATED_PE> relatedMap)
+    {
+        super.set(context, creationsMap, relatedMap);
+
+        daoFactory.getSessionFactory().getCurrentSession().flush();
+
+        reindexObjectExecutor.reindex(context, getRelatedClass(), relatedMap.values());
+    }
+
+    @Override
+    protected void setRelated(IOperationContext context, MetaprojectPE entity, Collection<RELATED_PE> related)
+    {
+        for (RELATED_PE aRelated : related)
+        {
+            aRelated.addMetaproject(entity);
+        }
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagExperimentsExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagExperimentsExecutor.java
new file mode 100644
index 00000000000..de756c94980
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagExperimentsExecutor.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.UnauthorizedObjectAccessException;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.AbstractSetEntityMultipleRelationsExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.experiment.IMapExperimentByIdExecutor;
+import ch.systemsx.cisd.openbis.generic.server.authorization.validator.ExperimentByIdentiferValidator;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class SetTagExperimentsExecutor extends AbstractSetEntityMultipleRelationsExecutor<TagCreation, MetaprojectPE, IExperimentId, ExperimentPE>
+        implements ISetTagExperimentsExecutor
+{
+
+    @Autowired
+    private IMapExperimentByIdExecutor mapExperimentExecutor;
+
+    @Autowired
+    private ISetTagExperimentsWithCacheExecutor setTagExperimentsWithCacheExecutor;
+
+    @Override
+    protected void addRelatedIds(Set<IExperimentId> relatedIds, TagCreation creation, MetaprojectPE entity)
+    {
+        addRelatedIds(relatedIds, creation.getExperimentIds());
+    }
+
+    @Override
+    protected void addRelated(Map<IExperimentId, ExperimentPE> relatedMap, TagCreation creation, MetaprojectPE entity)
+    {
+        // nothing to do here
+    }
+
+    @Override
+    protected Map<IExperimentId, ExperimentPE> map(IOperationContext context, List<IExperimentId> relatedIds)
+    {
+        return mapExperimentExecutor.map(context, relatedIds);
+    }
+
+    @Override
+    protected void check(IOperationContext context, IExperimentId relatedId, ExperimentPE related)
+    {
+        if (false == new ExperimentByIdentiferValidator().doValidation(context.getSession().tryGetPerson(), related))
+        {
+            throw new UnauthorizedObjectAccessException(relatedId);
+        }
+    }
+
+    @Override
+    protected void set(IOperationContext context, Map<TagCreation, MetaprojectPE> creationsMap, Map<IExperimentId, ExperimentPE> relatedMap)
+    {
+        setTagExperimentsWithCacheExecutor.set(context, creationsMap, relatedMap);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagExperimentsWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagExperimentsWithCacheExecutor.java
new file mode 100644
index 00000000000..20a763b243b
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagExperimentsWithCacheExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import java.util.Collection;
+
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.systemsx.cisd.openbis.generic.shared.dto.ExperimentPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class SetTagExperimentsWithCacheExecutor extends SetTagEntitiesWithCacheExecutor<IExperimentId, ExperimentPE>
+        implements ISetTagExperimentsWithCacheExecutor
+{
+
+    @Override
+    protected Class<ExperimentPE> getRelatedClass()
+    {
+        return ExperimentPE.class;
+    }
+
+    @Override
+    protected Collection<? extends IExperimentId> getRelatedIds(IOperationContext context, TagCreation creation)
+    {
+        return creation.getExperimentIds();
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagSamplesExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagSamplesExecutor.java
new file mode 100644
index 00000000000..f4533130cef
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagSamplesExecutor.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.exceptions.UnauthorizedObjectAccessException;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.AbstractSetEntityMultipleRelationsExecutor;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.sample.IMapSampleByIdExecutor;
+import ch.systemsx.cisd.openbis.generic.server.authorization.validator.SampleByIdentiferValidator;
+import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class SetTagSamplesExecutor extends AbstractSetEntityMultipleRelationsExecutor<TagCreation, MetaprojectPE, ISampleId, SamplePE>
+        implements ISetTagSamplesExecutor
+{
+
+    @Autowired
+    private IMapSampleByIdExecutor mapSampleExecutor;
+
+    @Autowired
+    private ISetTagSamplesWithCacheExecutor setTagSamplesWithCacheExecutor;
+
+    @Override
+    protected void addRelatedIds(Set<ISampleId> relatedIds, TagCreation creation, MetaprojectPE entity)
+    {
+        addRelatedIds(relatedIds, creation.getSampleIds());
+    }
+
+    @Override
+    protected void addRelated(Map<ISampleId, SamplePE> relatedMap, TagCreation creation, MetaprojectPE entity)
+    {
+        // nothing to do here
+    }
+
+    @Override
+    protected Map<ISampleId, SamplePE> map(IOperationContext context, List<ISampleId> relatedIds)
+    {
+        return mapSampleExecutor.map(context, relatedIds);
+    }
+
+    @Override
+    protected void check(IOperationContext context, ISampleId relatedId, SamplePE related)
+    {
+        if (false == new SampleByIdentiferValidator().doValidation(context.getSession().tryGetPerson(), related))
+        {
+            throw new UnauthorizedObjectAccessException(relatedId);
+        }
+    }
+
+    @Override
+    protected void set(IOperationContext context, Map<TagCreation, MetaprojectPE> creationsMap, Map<ISampleId, SamplePE> relatedMap)
+    {
+        setTagSamplesWithCacheExecutor.set(context, creationsMap, relatedMap);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagSamplesWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagSamplesWithCacheExecutor.java
new file mode 100644
index 00000000000..ffea2d97df1
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/SetTagSamplesWithCacheExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.generic.server.asapi.v3.executor.tag;
+
+import java.util.Collection;
+
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class SetTagSamplesWithCacheExecutor extends SetTagEntitiesWithCacheExecutor<ISampleId, SamplePE>
+        implements ISetTagSamplesWithCacheExecutor
+{
+
+    @Override
+    protected Class<SamplePE> getRelatedClass()
+    {
+        return SamplePE.class;
+    }
+
+    @Override
+    protected Collection<? extends ISampleId> getRelatedIds(IOperationContext context, TagCreation creation)
+    {
+        return creation.getSampleIds();
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagDataSetsWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagDataSetsWithCacheExecutor.java
index ece5c87c35d..52fdce7a2bc 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagDataSetsWithCacheExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagDataSetsWithCacheExecutor.java
@@ -32,7 +32,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
  * @author pkupczyk
  */
 @Component
-public class UpdateTagDataSetsWithCacheExecutor extends UpdateTagEntitiesExecutor<IDataSetId, DataPE> implements IUpdateTagDataSetsWithCacheExecutor
+public class UpdateTagDataSetsWithCacheExecutor extends UpdateTagEntitiesWithCacheExecutor<IDataSetId, DataPE> implements IUpdateTagDataSetsWithCacheExecutor
 {
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagEntitiesExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagEntitiesWithCacheExecutor.java
similarity index 77%
rename from openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagEntitiesExecutor.java
rename to openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagEntitiesWithCacheExecutor.java
index 9d9d96aed04..5a5680ce563 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagEntitiesExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagEntitiesWithCacheExecutor.java
@@ -25,10 +25,9 @@ import org.springframework.beans.factory.annotation.Autowired;
 
 import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.update.TagUpdate;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.common.IReindexObjectExecutor;
 import ch.ethz.sis.openbis.generic.server.asapi.v3.executor.entity.AbstractUpdateEntityToManyRelationExecutor;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
-import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IFullTextIndexUpdateScheduler;
-import ch.systemsx.cisd.openbis.generic.server.dataaccess.db.search.IndexUpdateOperation;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityWithMetaprojects;
 import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectAssignmentPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
@@ -36,13 +35,16 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
 /**
  * @author pkupczyk
  */
-public abstract class UpdateTagEntitiesExecutor<RELATED_ID, RELATED_PE extends IEntityWithMetaprojects>
+public abstract class UpdateTagEntitiesWithCacheExecutor<RELATED_ID, RELATED_PE extends IEntityWithMetaprojects>
         extends AbstractUpdateEntityToManyRelationExecutor<TagUpdate, MetaprojectPE, RELATED_ID, RELATED_PE>
 {
 
     @Autowired
     private IDAOFactory daoFactory;
 
+    @Autowired
+    private IReindexObjectExecutor reindexObjectExecutor;
+
     protected abstract Class<RELATED_PE> getRelatedClass();
 
     protected abstract RELATED_PE getCurrentlyRelated(MetaprojectAssignmentPE entity);
@@ -54,21 +56,7 @@ public abstract class UpdateTagEntitiesExecutor<RELATED_ID, RELATED_PE extends I
 
         daoFactory.getSessionFactory().getCurrentSession().flush();
 
-        IFullTextIndexUpdateScheduler indexUpdater = daoFactory.getPersistencyResources().getIndexUpdateScheduler();
-        List<Long> relatedIds = new ArrayList<Long>();
-
-        for (RELATED_PE related : relatedMap.values())
-        {
-            if (related != null)
-            {
-                relatedIds.add(related.getId());
-            }
-        }
-
-        if (false == relatedIds.isEmpty())
-        {
-            indexUpdater.scheduleUpdate(IndexUpdateOperation.reindex(getRelatedClass(), relatedIds));
-        }
+        reindexObjectExecutor.reindex(context, getRelatedClass(), relatedMap.values());
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagExperimentsWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagExperimentsWithCacheExecutor.java
index 7bbed276a12..ab7bb302cf4 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagExperimentsWithCacheExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagExperimentsWithCacheExecutor.java
@@ -32,7 +32,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
  * @author pkupczyk
  */
 @Component
-public class UpdateTagExperimentsWithCacheExecutor extends UpdateTagEntitiesExecutor<IExperimentId, ExperimentPE>
+public class UpdateTagExperimentsWithCacheExecutor extends UpdateTagEntitiesWithCacheExecutor<IExperimentId, ExperimentPE>
         implements IUpdateTagExperimentsWithCacheExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagMaterialsWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagMaterialsWithCacheExecutor.java
index 8b9ff6f2a6c..55eddd259f8 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagMaterialsWithCacheExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagMaterialsWithCacheExecutor.java
@@ -30,7 +30,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.MetaprojectPE;
  * @author pkupczyk
  */
 @Component
-public class UpdateTagMaterialsWithCacheExecutor extends UpdateTagEntitiesExecutor<IMaterialId, MaterialPE>
+public class UpdateTagMaterialsWithCacheExecutor extends UpdateTagEntitiesWithCacheExecutor<IMaterialId, MaterialPE>
         implements IUpdateTagMaterialsWithCacheExecutor
 {
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagSamplesWithCacheExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagSamplesWithCacheExecutor.java
index b10dddce7dd..78b1632a78b 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagSamplesWithCacheExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/asapi/v3/executor/tag/UpdateTagSamplesWithCacheExecutor.java
@@ -32,7 +32,7 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.SamplePE;
  * @author pkupczyk
  */
 @Component
-public class UpdateTagSamplesWithCacheExecutor extends UpdateTagEntitiesExecutor<ISampleId, SamplePE>
+public class UpdateTagSamplesWithCacheExecutor extends UpdateTagEntitiesWithCacheExecutor<ISampleId, SamplePE>
         implements IUpdateTagSamplesWithCacheExecutor
 {
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/tag/create/TagCreation.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/tag/create/TagCreation.js
index 51f55b8d5a7..687279feed9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/tag/create/TagCreation.js
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/resources/api/v3/as/dto/tag/create/TagCreation.js
@@ -9,6 +9,10 @@ define([ "stjs" ], function(stjs) {
 		constructor.serialVersionUID = 1;
 		prototype.code = null;
 		prototype.description = null;
+		prototype.experimentIds = null;
+		prototype.sampleIds = null;
+		prototype.dataSetIds = null;
+		prototype.materialIds = null;
 
 		prototype.getCode = function() {
 			return this.code;
@@ -22,6 +26,47 @@ define([ "stjs" ], function(stjs) {
 		prototype.setDescription = function(description) {
 			this.description = description;
 		};
-	}, {});
+		prototype.getExperimentIds = function() {
+			return this.experimentIds;
+		};
+		prototype.setExperimentIds = function(experimentIds) {
+			this.experimentIds = experimentIds;
+		};
+		prototype.getSampleIds = function() {
+			return this.sampleIds;
+		};
+		prototype.setSampleIds = function(sampleIds) {
+			this.sampleIds = sampleIds;
+		};
+		prototype.getDataSetIds = function() {
+			return this.dataSetIds;
+		};
+		prototype.setDataSetIds = function(dataSetIds) {
+			this.dataSetIds = dataSetIds;
+		};
+		prototype.getMaterialIds = function() {
+			return this.materialIds;
+		};
+		prototype.setMaterialIds = function(materialIds) {
+			this.materialIds = materialIds;
+		};
+	}, {
+		experimentIds : {
+			name : "List",
+			arguments : [ "Object" ]
+		},
+		sampleIds : {
+			name : "List",
+			arguments : [ "Object" ]
+		},
+		dataSetIds : {
+			name : "List",
+			arguments : [ "Object" ]
+		},
+		materialIds : {
+			name : "List",
+			arguments : [ "Object" ]
+		}
+	});
 	return TagCreation;
 })
\ No newline at end of file
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/CreateTagTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/CreateTagTest.java
new file mode 100644
index 00000000000..33b77f03c9e
--- /dev/null
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/asapi/v3/CreateTagTest.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2016 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.ethz.sis.openbis.systemtest.asapi.v3;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.ExperimentIdentifier;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.SampleIdentifier;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.Tag;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create.TagCreation;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.fetchoptions.TagFetchOptions;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.id.ITagId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.id.TagPermId;
+import ch.systemsx.cisd.common.action.IDelegatedAction;
+
+/**
+ * @author pkupczyk
+ */
+@Test(groups = { "before remote api" })
+public class CreateTagTest extends AbstractTest
+{
+
+    @Test
+    public void testCreateWithCodeNull()
+    {
+        assertUserFailureException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    TagCreation creation = new TagCreation();
+
+                    createTag(TEST_USER, PASSWORD, creation);
+                }
+            }, "Code cannot be empty");
+    }
+
+    @Test
+    public void testCreateWithCodeExisting()
+    {
+        assertUserFailureException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    TagCreation creation = new TagCreation();
+                    creation.setCode("TEST_METAPROJECTS");
+
+                    createTag(TEST_USER, PASSWORD, creation);
+                }
+            }, "Tag already exists in the database and needs to be unique");
+    }
+
+    @Test
+    public void testCreateWithCodeIncorrect()
+    {
+        assertUserFailureException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    TagCreation creation = new TagCreation();
+                    creation.setCode("i am incorrect");
+
+                    createTag(TEST_USER, PASSWORD, creation);
+                }
+            }, "Tag name cannot contain white spaces, commas, slashes or backslashes");
+    }
+
+    @Test
+    public void testCreateWithDescription()
+    {
+        TagCreation creation = new TagCreation();
+        creation.setCode("TEST_TAG");
+        creation.setDescription("test description");
+
+        Tag tag = createTag(TEST_USER, PASSWORD, creation);
+
+        assertEquals(tag.getDescription(), creation.getDescription());
+    }
+
+    @Test
+    public void testCreateWithExperiments()
+    {
+        final ExperimentIdentifier experimentId = new ExperimentIdentifier("/CISD/NEMO/EXP10");
+
+        TagCreation creation = new TagCreation();
+        creation.setCode("TEST_TAG");
+        creation.setExperimentIds(Arrays.asList(experimentId));
+
+        Tag tag = createTag(TEST_USER, PASSWORD, creation);
+
+        assertExperimentIdentifiers(tag.getExperiments(), experimentId.getIdentifier());
+    }
+
+    @Test
+    public void testCreateWithExperimentsUnauthorized()
+    {
+        final ExperimentIdentifier experimentId = new ExperimentIdentifier("/CISD/NEMO/EXP10");
+
+        assertUnauthorizedObjectAccessException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    TagCreation creation = new TagCreation();
+                    creation.setCode("TEST_TAG");
+                    creation.setExperimentIds(Arrays.asList(experimentId));
+
+                    createTag(TEST_SPACE_USER, PASSWORD, creation);
+                }
+            }, experimentId);
+    }
+
+    @Test
+    public void testCreateWithExperimentsNonexistent()
+    {
+        final ExperimentIdentifier experimentId = new ExperimentIdentifier("/CISD/NEMO/IDONTEXIST");
+
+        assertObjectNotFoundException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    TagCreation creation = new TagCreation();
+                    creation.setCode("TEST_TAG");
+                    creation.setExperimentIds(Arrays.asList(experimentId));
+
+                    createTag(TEST_USER, PASSWORD, creation);
+                }
+            }, experimentId);
+    }
+
+    @Test
+    public void testCreateWithSamples()
+    {
+        final SampleIdentifier sampleId = new SampleIdentifier("/CISD/CP-TEST-1");
+
+        TagCreation creation = new TagCreation();
+        creation.setCode("TEST_TAG");
+        creation.setSampleIds(Arrays.asList(sampleId));
+
+        Tag tag = createTag(TEST_USER, PASSWORD, creation);
+
+        assertSampleIdentifiers(tag.getSamples(), sampleId.getIdentifier());
+    }
+
+    @Test
+    public void testCreateWithSamplesUnauthorized()
+    {
+        final SampleIdentifier sampleId = new SampleIdentifier("/CISD/CP-TEST-1");
+
+        assertUnauthorizedObjectAccessException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    TagCreation creation = new TagCreation();
+                    creation.setCode("TEST_TAG");
+                    creation.setSampleIds(Arrays.asList(sampleId));
+
+                    createTag(TEST_SPACE_USER, PASSWORD, creation);
+                }
+            }, sampleId);
+    }
+
+    @Test
+    public void testCreateWithSamplesNonexistent()
+    {
+        final SampleIdentifier sampleId = new SampleIdentifier("/CISD/IDONTEXIST");
+
+        assertObjectNotFoundException(new IDelegatedAction()
+            {
+                @Override
+                public void execute()
+                {
+                    TagCreation creation = new TagCreation();
+                    creation.setCode("TEST_TAG");
+                    creation.setSampleIds(Arrays.asList(sampleId));
+
+                    createTag(TEST_USER, PASSWORD, creation);
+                }
+            }, sampleId);
+    }
+
+    private Tag createTag(String user, String password, TagCreation creation)
+    {
+        String sessionToken = v3api.login(user, password);
+
+        List<TagPermId> ids = v3api.createTags(sessionToken, Arrays.asList(creation));
+
+        assertEquals(ids.size(), 1);
+
+        TagFetchOptions fetchOptions = new TagFetchOptions();
+        fetchOptions.withExperiments();
+        fetchOptions.withSamples();
+        fetchOptions.withDataSets();
+        fetchOptions.withMaterials();
+
+        Map<ITagId, Tag> map = v3api.mapTags(sessionToken, ids, fetchOptions);
+
+        assertEquals(map.size(), 1);
+
+        return map.get(ids.get(0));
+    }
+
+}
diff --git a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/tag/create/TagCreation.java b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/tag/create/TagCreation.java
index de34417a392..89b7fcc8a45 100644
--- a/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/tag/create/TagCreation.java
+++ b/openbis_api/source/java/ch/ethz/sis/openbis/generic/asapi/v3/dto/tag/create/TagCreation.java
@@ -17,7 +17,12 @@
 package ch.ethz.sis.openbis.generic.asapi.v3.dto.tag.create;
 
 import java.io.Serializable;
+import java.util.List;
 
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.dataset.id.IDataSetId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.experiment.id.IExperimentId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.material.id.IMaterialId;
+import ch.ethz.sis.openbis.generic.asapi.v3.dto.sample.id.ISampleId;
 import ch.systemsx.cisd.base.annotation.JsonObject;
 
 /**
@@ -32,6 +37,14 @@ public class TagCreation implements Serializable
 
     private String description;
 
+    private List<? extends IExperimentId> experimentIds;
+
+    private List<? extends ISampleId> sampleIds;
+
+    private List<? extends IDataSetId> dataSetIds;
+
+    private List<? extends IMaterialId> materialIds;
+
     public String getCode()
     {
         return code;
@@ -52,4 +65,44 @@ public class TagCreation implements Serializable
         this.description = description;
     }
 
+    public List<? extends IExperimentId> getExperimentIds()
+    {
+        return experimentIds;
+    }
+
+    public void setExperimentIds(List<? extends IExperimentId> experimentIds)
+    {
+        this.experimentIds = experimentIds;
+    }
+
+    public List<? extends ISampleId> getSampleIds()
+    {
+        return sampleIds;
+    }
+
+    public void setSampleIds(List<? extends ISampleId> sampleIds)
+    {
+        this.sampleIds = sampleIds;
+    }
+
+    public List<? extends IDataSetId> getDataSetIds()
+    {
+        return dataSetIds;
+    }
+
+    public void setDataSetIds(List<? extends IDataSetId> dataSetIds)
+    {
+        this.dataSetIds = dataSetIds;
+    }
+
+    public List<? extends IMaterialId> getMaterialIds()
+    {
+        return materialIds;
+    }
+
+    public void setMaterialIds(List<? extends IMaterialId> materialIds)
+    {
+        this.materialIds = materialIds;
+    }
+
 }
diff --git a/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt b/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt
index 4e56f69d794..0b05d31cc93 100644
--- a/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt
+++ b/openbis_api/sourceTest/java/ch/ethz/sis/openbis/generic/sharedapi/v3/dictionary.txt
@@ -1126,4 +1126,8 @@ set Tag Id
 Tag Update
 update Tags
 create Tags
-Tag Creation
\ No newline at end of file
+Tag Creation
+set DataSet Ids
+set Experiment Ids
+set Material Ids
+set Sample Ids
\ No newline at end of file
-- 
GitLab