From 286d680d66fe46a6df37b517c6ae12b202bced13 Mon Sep 17 00:00:00 2001
From: pkupczyk <pkupczyk>
Date: Mon, 27 Jul 2015 09:43:25 +0000
Subject: [PATCH] SSDM-1771 : V3 AS API - create tests to verify whether the
 capabilities work in the new API

SVN: 34372
---
 openbis/etc/capabilities                      |  1 +
 .../server/api/v3/ApplicationServerApi.java   | 24 ++++-----
 .../server/api/v3/context/IContext.java       |  4 +-
 ...ractUpdateAttachmentForEntityExecutor.java | 31 ++++++++++++
 .../IUpdateAttachmentForEntityExecutor.java   |  8 +--
 .../IUpdateDataSetPropertyExecutor.java       | 27 ++++++++++
 .../dataset/UpdateDataSetExecutor.java        | 14 ++++--
 .../UpdateDataSetPropertyExecutor.java        | 49 +++++++++++++++++++
 .../IUpdateExperimentAttachmentExecutor.java  | 27 ++++++++++
 .../IUpdateExperimentPropertyExecutor.java    | 27 ++++++++++
 .../UpdateExperimentAttachmentExecutor.java   | 48 ++++++++++++++++++
 .../experiment/UpdateExperimentExecutor.java  | 23 ++++++---
 .../UpdateExperimentPropertyExecutor.java     | 49 +++++++++++++++++++
 .../IUpdateMaterialPropertyExecutor.java      | 27 ++++++++++
 .../material/UpdateMaterialExecutor.java      | 14 ++++--
 .../UpdateMaterialPropertyExecutor.java       | 49 +++++++++++++++++++
 .../IUpdateProjectAttachmentExecutor.java     | 27 ++++++++++
 .../UpdateProjectAttachmentExecutor.java      | 48 ++++++++++++++++++
 .../project/UpdateProjectExecutor.java        |  8 +--
 ...IAbstractUpdateEntityPropertyExecutor.java | 32 ++++++++++++
 .../IUpdateEntityPropertyExecutor.java        |  9 +---
 .../IUpdateSampleAttachmentExecutor.java      | 27 ++++++++++
 .../sample/IUpdateSamplePropertyExecutor.java | 27 ++++++++++
 .../UpdateSampleAttachmentExecutor.java       | 48 ++++++++++++++++++
 .../executor/sample/UpdateSampleExecutor.java | 23 ++++++---
 .../sample/UpdateSamplePropertyExecutor.java  | 49 +++++++++++++++++++
 .../authorization/AuthorizationAdvisor.java   |  8 ++-
 .../shared/dto/IAuthSessionProvider.java      | 27 ++++++++++
 .../systemtest/api/v3/CreateProjectTest.java  | 13 +++++
 openbis/sourceTest/java/tests_v3_api.xml      | 19 ++++---
 30 files changed, 726 insertions(+), 61 deletions(-)
 create mode 100644 openbis/etc/capabilities
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/attachment/IAbstractUpdateAttachmentForEntityExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/IUpdateDataSetPropertyExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/UpdateDataSetPropertyExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/IUpdateExperimentAttachmentExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/IUpdateExperimentPropertyExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentAttachmentExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentPropertyExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/IUpdateMaterialPropertyExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/UpdateMaterialPropertyExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/IUpdateProjectAttachmentExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/UpdateProjectAttachmentExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/property/IAbstractUpdateEntityPropertyExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IUpdateSampleAttachmentExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IUpdateSamplePropertyExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSampleAttachmentExecutor.java
 create mode 100644 openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSamplePropertyExecutor.java
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/IAuthSessionProvider.java

diff --git a/openbis/etc/capabilities b/openbis/etc/capabilities
new file mode 100644
index 00000000000..ea311842c52
--- /dev/null
+++ b/openbis/etc/capabilities
@@ -0,0 +1 @@
+REGISTER_PROJECT: SPACE_OBSERVER
\ No newline at end of file
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
index 8a9928e4486..004d0f4b467 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/ApplicationServerApi.java
@@ -258,7 +258,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.SPACE_ADMIN, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("REGISTER_SPACE")
+    @Capability("CREATE_SPACE")
     @DatabaseCreateOrDeleteModification(value = ObjectKind.SPACE)
     public List<SpacePermId> createSpaces(String sessionToken, List<SpaceCreation> creations)
     {
@@ -268,7 +268,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("REGISTER_PROJECT")
+    @Capability("CREATE_PROJECT")
     @DatabaseCreateOrDeleteModification(value = ObjectKind.PROJECT)
     public List<ProjectPermId> createProjects(String sessionToken, List<ProjectCreation> creations)
     {
@@ -278,7 +278,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("WRITE_EXPERIMENT")
+    @Capability("CREATE_EXPERIMENT")
     @DatabaseCreateOrDeleteModification(value = ObjectKind.EXPERIMENT)
     public List<ExperimentPermId> createExperiments(String sessionToken,
             List<ExperimentCreation> creations)
@@ -289,7 +289,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("WRITE_SAMPLE")
+    @Capability("CREATE_SAMPLE")
     @DatabaseCreateOrDeleteModification(value = ObjectKind.SAMPLE)
     public List<SamplePermId> createSamples(String sessionToken,
             List<SampleCreation> creations)
@@ -300,7 +300,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.INSTANCE_ADMIN, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("WRITE_MATERIAL")
+    @Capability("CREATE_MATERIAL")
     @DatabaseCreateOrDeleteModification(value = ObjectKind.MATERIAL)
     public List<MaterialPermId> createMaterials(String sessionToken, List<MaterialCreation> creations)
     {
@@ -320,7 +320,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("WRITE_PROJECT")
+    @Capability("UPDATE_PROJECT")
     @DatabaseUpdateModification(value = ObjectKind.PROJECT)
     public void updateProjects(String sessionToken, List<ProjectUpdate> updates)
     {
@@ -330,7 +330,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("WRITE_EXPERIMENT")
+    @Capability("UPDATE_EXPERIMENT")
     @DatabaseUpdateModification(value = ObjectKind.EXPERIMENT)
     public void updateExperiments(String sessionToken, List<ExperimentUpdate> updates)
     {
@@ -340,7 +340,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("WRITE_SAMPLE")
+    @Capability("UPDATE_SAMPLE")
     @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
     public void updateSamples(String sessionToken, List<SampleUpdate> updates)
     {
@@ -360,7 +360,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Override
     @Transactional
     @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("WRITE_DATASET")
+    @Capability("UPDATE_DATASET")
     @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     public void updateDataSets(String sessionToken, List<DataSetUpdate> updates)
     {
@@ -510,7 +510,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Transactional
     @DatabaseCreateOrDeleteModification(value = { ObjectKind.DATA_SET, ObjectKind.DELETION })
     @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("DELETE_DATA_SET")
+    @Capability("DELETE_DATASET")
     public IDeletionId deleteDataSets(String sessionToken, List<? extends IDataSetId> dataSetIds, DataSetDeletionOptions deletionOptions)
     {
         return deleteDataSetExecutor.delete(sessionToken, dataSetIds, deletionOptions);
@@ -539,7 +539,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @DatabaseCreateOrDeleteModification(value = ObjectKind.DELETION)
     @DatabaseUpdateModification(value = { ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("RESTORE")
+    @Capability("REVERT_DELETION")
     public void revertDeletions(String sessionToken, List<? extends IDeletionId> deletionIds)
     {
         revertDeletionExecutor.revert(sessionToken, deletionIds);
@@ -549,7 +549,7 @@ public class ApplicationServerApi extends AbstractServer<IApplicationServerApi>
     @Transactional
     @DatabaseCreateOrDeleteModification(value = { ObjectKind.DELETION, ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     @RolesAllowed({ RoleWithHierarchy.SPACE_ADMIN, RoleWithHierarchy.SPACE_ETL_SERVER })
-    @Capability("PURGE")
+    @Capability("CONFIRM_DELETION")
     public void confirmDeletions(String sessionToken, List<? extends IDeletionId> deletionIds)
     {
         confirmDeletionExecutor.confirm(sessionToken, deletionIds);
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/context/IContext.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/context/IContext.java
index d7010c564cc..164417838d5 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/context/IContext.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/context/IContext.java
@@ -18,12 +18,13 @@ package ch.ethz.sis.openbis.generic.server.api.v3.context;
 
 import java.util.Collection;
 
+import ch.systemsx.cisd.openbis.generic.shared.dto.IAuthSessionProvider;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
 
 /**
  * @author pkupczyk
  */
-public interface IContext
+public interface IContext extends IAuthSessionProvider
 {
 
     public void pushContextDescription(String description);
@@ -32,6 +33,7 @@ public interface IContext
 
     public Collection<String> getContextDescriptions();
 
+    @Override
     public Session getSession();
 
     public Object getAttribute(String attributeName);
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/attachment/IAbstractUpdateAttachmentForEntityExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/attachment/IAbstractUpdateAttachmentForEntityExecutor.java
new file mode 100644
index 00000000000..59510a4e14d
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/attachment/IAbstractUpdateAttachmentForEntityExecutor.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.api.v3.executor.attachment;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.AttachmentListUpdateValue;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentHolderPE;
+
+/**
+ * @author pkupczyk
+ */
+public interface IAbstractUpdateAttachmentForEntityExecutor
+{
+
+    public void update(IOperationContext context, AttachmentHolderPE attachmentHolder, AttachmentListUpdateValue updates);
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/attachment/IUpdateAttachmentForEntityExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/attachment/IUpdateAttachmentForEntityExecutor.java
index 6e90d17d195..41fdd277ec8 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/attachment/IUpdateAttachmentForEntityExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/attachment/IUpdateAttachmentForEntityExecutor.java
@@ -16,16 +16,10 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment;
 
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
-import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.AttachmentListUpdateValue;
-import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentHolderPE;
-
 /**
  * @author pkupczyk
  */
-public interface IUpdateAttachmentForEntityExecutor
+public interface IUpdateAttachmentForEntityExecutor extends IAbstractUpdateAttachmentForEntityExecutor
 {
 
-    public void update(IOperationContext context, AttachmentHolderPE attachmentHolder, AttachmentListUpdateValue updates);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/IUpdateDataSetPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/IUpdateDataSetPropertyExecutor.java
new file mode 100644
index 00000000000..eaea86132dd
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/IUpdateDataSetPropertyExecutor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.api.v3.executor.dataset;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IAbstractUpdateEntityPropertyExecutor;
+
+/**
+ * @author pkupczyk
+ */
+public interface IUpdateDataSetPropertyExecutor extends IAbstractUpdateEntityPropertyExecutor
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/UpdateDataSetExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/UpdateDataSetExecutor.java
index c80c7c1a95f..fd919f470c0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/UpdateDataSetExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/UpdateDataSetExecutor.java
@@ -27,7 +27,6 @@ import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.entity.AbstractUpdateEntityExecutor;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IUpdateEntityPropertyExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.IUpdateTagForEntityExecutor;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.dataset.DataSetUpdate;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.dataset.IDataSetId;
@@ -67,7 +66,7 @@ public class UpdateDataSetExecutor extends AbstractUpdateEntityExecutor<DataSetU
     private IUpdateDataSetRelatedDataSetsExecutor updateDataSetRelatedDataSetsExecutor;
 
     @Autowired
-    private IUpdateEntityPropertyExecutor updateEntityPropertyExecutor;
+    private IUpdateDataSetPropertyExecutor updateDataSetPropertyExecutor;
 
     @Autowired
     private IUpdateTagForEntityExecutor updateTagForEntityExecutor;
@@ -120,10 +119,17 @@ public class UpdateDataSetExecutor extends AbstractUpdateEntityExecutor<DataSetU
 
             RelationshipUtils.updateModificationDateAndModifier(entity, context.getSession().tryGetPerson());
             updateTagForEntityExecutor.update(context, entity, update.getTagIds());
-            propertyMap.put(entity, update.getProperties());
+
+            if (update.getProperties() != null && false == update.getProperties().isEmpty())
+            {
+                propertyMap.put(entity, update.getProperties());
+            }
         }
 
-        updateEntityPropertyExecutor.update(context, propertyMap);
+        if (false == propertyMap.isEmpty())
+        {
+            updateDataSetPropertyExecutor.update(context, propertyMap);
+        }
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/UpdateDataSetPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/UpdateDataSetPropertyExecutor.java
new file mode 100644
index 00000000000..2acd6ef18c0
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/dataset/UpdateDataSetPropertyExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.api.v3.executor.dataset;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IUpdateEntityPropertyExecutor;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityPropertiesHolder;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class UpdateDataSetPropertyExecutor implements IUpdateDataSetPropertyExecutor
+{
+
+    @Autowired
+    private IUpdateEntityPropertyExecutor executor;
+
+    @Override
+    @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @Capability("UPDATE_DATASET_PROPERTY")
+    public void update(IOperationContext context, Map<IEntityPropertiesHolder, Map<String, String>> entityToPropertiesMap)
+    {
+        executor.update(context, entityToPropertiesMap);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/IUpdateExperimentAttachmentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/IUpdateExperimentAttachmentExecutor.java
new file mode 100644
index 00000000000..aad4e84a534
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/IUpdateExperimentAttachmentExecutor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.api.v3.executor.experiment;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IAbstractUpdateAttachmentForEntityExecutor;
+
+/**
+ * @author pkupczyk
+ */
+public interface IUpdateExperimentAttachmentExecutor extends IAbstractUpdateAttachmentForEntityExecutor
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/IUpdateExperimentPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/IUpdateExperimentPropertyExecutor.java
new file mode 100644
index 00000000000..13648289678
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/IUpdateExperimentPropertyExecutor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.api.v3.executor.experiment;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IAbstractUpdateEntityPropertyExecutor;
+
+/**
+ * @author pkupczyk
+ */
+public interface IUpdateExperimentPropertyExecutor extends IAbstractUpdateEntityPropertyExecutor
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentAttachmentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentAttachmentExecutor.java
new file mode 100644
index 00000000000..c0e364b7a21
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentAttachmentExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * 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.api.v3.executor.experiment;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IUpdateAttachmentForEntityExecutor;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.AttachmentListUpdateValue;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentHolderPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class UpdateExperimentAttachmentExecutor implements IUpdateExperimentAttachmentExecutor
+{
+
+    @Autowired
+    private IUpdateAttachmentForEntityExecutor executor;
+
+    @Override
+    @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @Capability("UPDATE_EXPERIMENT_ATTACHMENT")
+    public void update(IOperationContext context, AttachmentHolderPE attachmentHolder, AttachmentListUpdateValue updates)
+    {
+        executor.update(context, attachmentHolder, updates);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentExecutor.java
index 9917374ec65..f1768b74a1f 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentExecutor.java
@@ -26,9 +26,7 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IUpdateAttachmentForEntityExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.entity.AbstractUpdateEntityExecutor;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IUpdateEntityPropertyExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.IUpdateTagForEntityExecutor;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.experiment.ExperimentUpdate;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.experiment.IExperimentId;
@@ -60,13 +58,13 @@ public class UpdateExperimentExecutor extends AbstractUpdateEntityExecutor<Exper
     private IUpdateExperimentProjectExecutor updateExperimentProjectExecutor;
 
     @Autowired
-    private IUpdateEntityPropertyExecutor updateEntityPropertyExecutor;
+    private IUpdateExperimentPropertyExecutor updateExperimentPropertyExecutor;
 
     @Autowired
     private IUpdateTagForEntityExecutor updateTagForEntityExecutor;
 
     @Autowired
-    private IUpdateAttachmentForEntityExecutor updateAttachmentForEntityExecutor;
+    private IUpdateExperimentAttachmentExecutor updateExperimentAttachmentExecutor;
 
     @Autowired
     private IVerifyExperimentExecutor verifyExperimentExecutor;
@@ -114,11 +112,22 @@ public class UpdateExperimentExecutor extends AbstractUpdateEntityExecutor<Exper
 
             RelationshipUtils.updateModificationDateAndModifier(entity, context.getSession().tryGetPerson());
             updateTagForEntityExecutor.update(context, entity, update.getTagIds());
-            updateAttachmentForEntityExecutor.update(context, entity, update.getAttachments());
-            propertyMap.put(entity, update.getProperties());
+
+            if (update.getAttachments() != null && update.getAttachments().hasActions())
+            {
+                updateExperimentAttachmentExecutor.update(context, entity, update.getAttachments());
+            }
+
+            if (update.getProperties() != null && false == update.getProperties().isEmpty())
+            {
+                propertyMap.put(entity, update.getProperties());
+            }
         }
 
-        updateEntityPropertyExecutor.update(context, propertyMap);
+        if (false == propertyMap.isEmpty())
+        {
+            updateExperimentPropertyExecutor.update(context, propertyMap);
+        }
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentPropertyExecutor.java
new file mode 100644
index 00000000000..13c093ea3cc
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/experiment/UpdateExperimentPropertyExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.api.v3.executor.experiment;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IUpdateEntityPropertyExecutor;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityPropertiesHolder;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class UpdateExperimentPropertyExecutor implements IUpdateExperimentPropertyExecutor
+{
+
+    @Autowired
+    private IUpdateEntityPropertyExecutor executor;
+
+    @Override
+    @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @Capability("UPDATE_EXPERIMENT_PROPERTY")
+    public void update(IOperationContext context, Map<IEntityPropertiesHolder, Map<String, String>> entityToPropertiesMap)
+    {
+        executor.update(context, entityToPropertiesMap);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/IUpdateMaterialPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/IUpdateMaterialPropertyExecutor.java
new file mode 100644
index 00000000000..bf0c38f7255
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/IUpdateMaterialPropertyExecutor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.api.v3.executor.material;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IAbstractUpdateEntityPropertyExecutor;
+
+/**
+ * @author pkupczyk
+ */
+public interface IUpdateMaterialPropertyExecutor extends IAbstractUpdateEntityPropertyExecutor
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/UpdateMaterialExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/UpdateMaterialExecutor.java
index d14bcd1b026..165b17b0dd0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/UpdateMaterialExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/UpdateMaterialExecutor.java
@@ -27,7 +27,6 @@ import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.entity.AbstractUpdateEntityExecutor;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IUpdateEntityPropertyExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.IUpdateTagForEntityExecutor;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.material.MaterialUpdate;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.material.IMaterialId;
@@ -54,7 +53,7 @@ public class UpdateMaterialExecutor extends AbstractUpdateEntityExecutor<Materia
     private IMapMaterialByIdExecutor mapMaterialByIdExecutor;
 
     @Autowired
-    private IUpdateEntityPropertyExecutor updateEntityPropertyExecutor;
+    private IUpdateMaterialPropertyExecutor updateMaterialPropertyExecutor;
 
     @Autowired
     private IUpdateTagForEntityExecutor updateTagForEntityExecutor;
@@ -101,10 +100,17 @@ public class UpdateMaterialExecutor extends AbstractUpdateEntityExecutor<Materia
             MaterialUpdate update = entry.getKey();
             MaterialPE entity = entry.getValue();
             updateTagForEntityExecutor.update(context, entity, update.getTagIds());
-            propertyMap.put(entity, update.getProperties());
+
+            if (update.getProperties() != null && false == update.getProperties().isEmpty())
+            {
+                propertyMap.put(entity, update.getProperties());
+            }
         }
 
-        updateEntityPropertyExecutor.update(context, propertyMap);
+        if (false == propertyMap.isEmpty())
+        {
+            updateMaterialPropertyExecutor.update(context, propertyMap);
+        }
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/UpdateMaterialPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/UpdateMaterialPropertyExecutor.java
new file mode 100644
index 00000000000..27354f35701
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/material/UpdateMaterialPropertyExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.api.v3.executor.material;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IUpdateEntityPropertyExecutor;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityPropertiesHolder;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class UpdateMaterialPropertyExecutor implements IUpdateMaterialPropertyExecutor
+{
+
+    @Autowired
+    private IUpdateEntityPropertyExecutor executor;
+
+    @Override
+    @RolesAllowed({ RoleWithHierarchy.INSTANCE_ADMIN, RoleWithHierarchy.INSTANCE_ETL_SERVER })
+    @Capability("UPDATE_MATERIAL_PROPERTY")
+    public void update(IOperationContext context, Map<IEntityPropertiesHolder, Map<String, String>> entityToPropertiesMap)
+    {
+        executor.update(context, entityToPropertiesMap);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/IUpdateProjectAttachmentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/IUpdateProjectAttachmentExecutor.java
new file mode 100644
index 00000000000..3ecd5556ea6
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/IUpdateProjectAttachmentExecutor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.api.v3.executor.project;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IAbstractUpdateAttachmentForEntityExecutor;
+
+/**
+ * @author pkupczyk
+ */
+public interface IUpdateProjectAttachmentExecutor extends IAbstractUpdateAttachmentForEntityExecutor
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/UpdateProjectAttachmentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/UpdateProjectAttachmentExecutor.java
new file mode 100644
index 00000000000..40ef4d0213c
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/UpdateProjectAttachmentExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * 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.api.v3.executor.project;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IUpdateAttachmentForEntityExecutor;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.AttachmentListUpdateValue;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentHolderPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class UpdateProjectAttachmentExecutor implements IUpdateProjectAttachmentExecutor
+{
+
+    @Autowired
+    private IUpdateAttachmentForEntityExecutor executor;
+
+    @Override
+    @RolesAllowed({ RoleWithHierarchy.SPACE_POWER_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @Capability("UPDATE_PROJECT_ATTACHMENT")
+    public void update(IOperationContext context, AttachmentHolderPE attachmentHolder, AttachmentListUpdateValue updates)
+    {
+        executor.update(context, attachmentHolder, updates);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/UpdateProjectExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/UpdateProjectExecutor.java
index f9539480701..ba2756bacfb 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/UpdateProjectExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/project/UpdateProjectExecutor.java
@@ -25,7 +25,6 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IUpdateAttachmentForEntityExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.entity.AbstractUpdateEntityExecutor;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.project.ProjectUpdate;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.project.IProjectId;
@@ -55,7 +54,7 @@ public class UpdateProjectExecutor extends AbstractUpdateEntityExecutor<ProjectU
     private IUpdateProjectSpaceExecutor updateProjectSpaceExecutor;
 
     @Autowired
-    private IUpdateAttachmentForEntityExecutor updateAttachmentForEntityExecutor;
+    private IUpdateProjectAttachmentExecutor updateProjectAttachmentExecutor;
 
     @Override
     protected IProjectId getId(ProjectUpdate update)
@@ -104,7 +103,10 @@ public class UpdateProjectExecutor extends AbstractUpdateEntityExecutor<ProjectU
                 project.setDescription(update.getDescription().getValue());
             }
 
-            updateAttachmentForEntityExecutor.update(context, project, update.getAttachments());
+            if (update.getAttachments() != null && update.getAttachments().hasActions())
+            {
+                updateProjectAttachmentExecutor.update(context, project, update.getAttachments());
+            }
         }
     }
 
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/property/IAbstractUpdateEntityPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/property/IAbstractUpdateEntityPropertyExecutor.java
new file mode 100644
index 00000000000..42499886db9
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/property/IAbstractUpdateEntityPropertyExecutor.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2014 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.api.v3.executor.property;
+
+import java.util.Map;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityPropertiesHolder;
+
+/**
+ * @author pkupczyk
+ */
+public interface IAbstractUpdateEntityPropertyExecutor
+{
+
+    public void update(IOperationContext context, Map<IEntityPropertiesHolder, Map<String, String>> entityToPropertiesMap);
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/property/IUpdateEntityPropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/property/IUpdateEntityPropertyExecutor.java
index cf658b5f80f..8422f5aded0 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/property/IUpdateEntityPropertyExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/property/IUpdateEntityPropertyExecutor.java
@@ -16,17 +16,10 @@
 
 package ch.ethz.sis.openbis.generic.server.api.v3.executor.property;
 
-import java.util.Map;
-
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
-import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityPropertiesHolder;
-
 /**
  * @author pkupczyk
  */
-public interface IUpdateEntityPropertyExecutor
+public interface IUpdateEntityPropertyExecutor extends IAbstractUpdateEntityPropertyExecutor
 {
 
-    public void update(IOperationContext context, Map<IEntityPropertiesHolder, Map<String, String>> entityToPropertiesMap);
-
 }
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IUpdateSampleAttachmentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IUpdateSampleAttachmentExecutor.java
new file mode 100644
index 00000000000..d4ef122b2bf
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IUpdateSampleAttachmentExecutor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.api.v3.executor.sample;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IAbstractUpdateAttachmentForEntityExecutor;
+
+/**
+ * @author pkupczyk
+ */
+public interface IUpdateSampleAttachmentExecutor extends IAbstractUpdateAttachmentForEntityExecutor
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IUpdateSamplePropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IUpdateSamplePropertyExecutor.java
new file mode 100644
index 00000000000..ffb4a73fa7b
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/IUpdateSamplePropertyExecutor.java
@@ -0,0 +1,27 @@
+/*
+ * 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.api.v3.executor.sample;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IAbstractUpdateEntityPropertyExecutor;
+
+/**
+ * @author pkupczyk
+ */
+public interface IUpdateSamplePropertyExecutor extends IAbstractUpdateEntityPropertyExecutor
+{
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSampleAttachmentExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSampleAttachmentExecutor.java
new file mode 100644
index 00000000000..53eb634e520
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSampleAttachmentExecutor.java
@@ -0,0 +1,48 @@
+/*
+ * 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.api.v3.executor.sample;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IUpdateAttachmentForEntityExecutor;
+import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.AttachmentListUpdateValue;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+import ch.systemsx.cisd.openbis.generic.shared.dto.AttachmentHolderPE;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class UpdateSampleAttachmentExecutor implements IUpdateSampleAttachmentExecutor
+{
+
+    @Autowired
+    private IUpdateAttachmentForEntityExecutor executor;
+
+    @Override
+    @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @Capability("UPDATE_SAMPLE_ATTACHMENT")
+    public void update(IOperationContext context, AttachmentHolderPE attachmentHolder, AttachmentListUpdateValue updates)
+    {
+        executor.update(context, attachmentHolder, updates);
+    }
+
+}
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSampleExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSampleExecutor.java
index 77d2dd6a614..a7b17f10ed6 100644
--- a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSampleExecutor.java
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSampleExecutor.java
@@ -26,9 +26,7 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Component;
 
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.attachment.IUpdateAttachmentForEntityExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.entity.AbstractUpdateEntityExecutor;
-import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IUpdateEntityPropertyExecutor;
 import ch.ethz.sis.openbis.generic.server.api.v3.executor.tag.IUpdateTagForEntityExecutor;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.entity.sample.SampleUpdate;
 import ch.ethz.sis.openbis.generic.shared.api.v3.dto.id.sample.ISampleId;
@@ -65,13 +63,13 @@ public class UpdateSampleExecutor extends AbstractUpdateEntityExecutor<SampleUpd
     private IUpdateSampleRelatedSamplesExecutor updateSampleRelatedSamplesExecutor;
 
     @Autowired
-    private IUpdateEntityPropertyExecutor updateEntityPropertyExecutor;
+    private IUpdateSamplePropertyExecutor updateSamplePropertyExecutor;
 
     @Autowired
     private IUpdateTagForEntityExecutor updateTagForEntityExecutor;
 
     @Autowired
-    private IUpdateAttachmentForEntityExecutor updateAttachmentForEntityExecutor;
+    private IUpdateSampleAttachmentExecutor updateSampleAttachmentExecutor;
 
     @Autowired
     private IVerifySampleExecutor verifySampleExecutor;
@@ -120,11 +118,22 @@ public class UpdateSampleExecutor extends AbstractUpdateEntityExecutor<SampleUpd
 
             RelationshipUtils.updateModificationDateAndModifier(entity, context.getSession().tryGetPerson());
             updateTagForEntityExecutor.update(context, entity, update.getTagIds());
-            updateAttachmentForEntityExecutor.update(context, entity, update.getAttachments());
-            propertyMap.put(entity, update.getProperties());
+
+            if (update.getAttachments() != null && update.getAttachments().hasActions())
+            {
+                updateSampleAttachmentExecutor.update(context, entity, update.getAttachments());
+            }
+
+            if (update.getProperties() != null && false == update.getProperties().isEmpty())
+            {
+                propertyMap.put(entity, update.getProperties());
+            }
         }
 
-        updateEntityPropertyExecutor.update(context, propertyMap);
+        if (false == propertyMap.isEmpty())
+        {
+            updateSamplePropertyExecutor.update(context, propertyMap);
+        }
     }
 
     @Override
diff --git a/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSamplePropertyExecutor.java b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSamplePropertyExecutor.java
new file mode 100644
index 00000000000..13b94ec7d6f
--- /dev/null
+++ b/openbis/source/java/ch/ethz/sis/openbis/generic/server/api/v3/executor/sample/UpdateSamplePropertyExecutor.java
@@ -0,0 +1,49 @@
+/*
+ * 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.api.v3.executor.sample;
+
+import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.IOperationContext;
+import ch.ethz.sis.openbis.generic.server.api.v3.executor.property.IUpdateEntityPropertyExecutor;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.Capability;
+import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAllowed;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.RoleWithHierarchy;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IEntityPropertiesHolder;
+
+/**
+ * @author pkupczyk
+ */
+@Component
+public class UpdateSamplePropertyExecutor implements IUpdateSamplePropertyExecutor
+{
+
+    @Autowired
+    private IUpdateEntityPropertyExecutor executor;
+
+    @Override
+    @RolesAllowed({ RoleWithHierarchy.SPACE_USER, RoleWithHierarchy.SPACE_ETL_SERVER })
+    @Capability("UPDATE_SAMPLE_PROPERTY")
+    public void update(IOperationContext context, Map<IEntityPropertiesHolder, Map<String, String>> entityToPropertiesMap)
+    {
+        executor.update(context, entityToPropertiesMap);
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationAdvisor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationAdvisor.java
index e83dec0a9d2..be55b007db9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationAdvisor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/authorization/AuthorizationAdvisor.java
@@ -44,6 +44,7 @@ import ch.systemsx.cisd.openbis.generic.server.authorization.annotation.RolesAll
 import ch.systemsx.cisd.openbis.generic.server.util.MethodInvocationUtils;
 import ch.systemsx.cisd.openbis.generic.shared.ISessionProvider;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IAuthSession;
+import ch.systemsx.cisd.openbis.generic.shared.dto.IAuthSessionProvider;
 
 /**
  * The <i>openBIS</i> authorization {@link Advisor}.
@@ -122,7 +123,7 @@ public final class AuthorizationAdvisor extends DefaultPointcutAdvisor
         }
 
         @SuppressWarnings(
-            { "unchecked", "rawtypes" })
+        { "unchecked", "rawtypes" })
         private final static Argument<?> toArgument(final Parameter<AuthorizationGuard> parameter,
                 final Object[] args)
         {
@@ -178,6 +179,11 @@ public final class AuthorizationAdvisor extends DefaultPointcutAdvisor
                 IAuthSession session = (IAuthSession) firstObject;
                 return session;
             }
+            if (firstObject instanceof IAuthSessionProvider)
+            {
+                IAuthSessionProvider sessionProvider = (IAuthSessionProvider) firstObject;
+                return sessionProvider.getSession();
+            }
             if (firstObject instanceof String)
             {
                 String sessionToken = (String) firstObject;
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/IAuthSessionProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/IAuthSessionProvider.java
new file mode 100644
index 00000000000..fc5ea98ee15
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/dto/IAuthSessionProvider.java
@@ -0,0 +1,27 @@
+/*
+ * 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.systemsx.cisd.openbis.generic.shared.dto;
+
+/**
+ * @author pkupczyk
+ */
+public interface IAuthSessionProvider
+{
+
+    IAuthSession getSession();
+
+}
diff --git a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/CreateProjectTest.java b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/CreateProjectTest.java
index 2761818399e..dc73397cfe3 100644
--- a/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/CreateProjectTest.java
+++ b/openbis/sourceTest/java/ch/ethz/sis/openbis/systemtest/api/v3/CreateProjectTest.java
@@ -181,6 +181,19 @@ public class CreateProjectTest extends AbstractTest
             }, leaderId);
     }
 
+    @Test
+    public void testCreateWithCapabilitySet()
+    {
+        final String sessionToken = v3api.login(TEST_GROUP_OBSERVER, PASSWORD);
+
+        final ISpaceId spaceId = new SpacePermId("TESTGROUP");
+        final ProjectCreation project = new ProjectCreation();
+        project.setCode("CAN_I_DO_THIS");
+        project.setSpaceId(spaceId);
+
+        v3api.createProjects(sessionToken, Arrays.asList(project));
+    }
+
     @Test
     public void testCreateWithMultipleProjects()
     {
diff --git a/openbis/sourceTest/java/tests_v3_api.xml b/openbis/sourceTest/java/tests_v3_api.xml
index 730f21363e8..27d214b692d 100644
--- a/openbis/sourceTest/java/tests_v3_api.xml
+++ b/openbis/sourceTest/java/tests_v3_api.xml
@@ -1,8 +1,13 @@
-<suite name="v3" verbose="2" >
-  <test name="unit" annotations="JDK">
-    <packages>
-      <package name="ch.ethz.sis.openbis.generic.server.api.v3.*" />
-      <package name="ch.ethz.sis.openbis.systemtest.api.v3.*" />
-    </packages>     
-  </test>
+<suite name="v3" verbose="2">
+	<test name="unit" annotations="JDK">
+		<groups>
+			<run>
+				<exclude name="system-cleandb" />
+			</run>
+		</groups>
+		<packages>
+			<package name="ch.ethz.sis.openbis.generic.server.api.v3.*" />
+			<package name="ch.ethz.sis.openbis.systemtest.api.v3.*" />
+		</packages>
+	</test>
 </suite>
-- 
GitLab