From 0bbc3fa37dc4d061b4eab9d0410a71e7cac40fbc Mon Sep 17 00:00:00 2001
From: buczekp <buczekp>
Date: Wed, 13 Jul 2011 13:09:17 +0000
Subject: [PATCH] [LMS-2365] implemented revert of deletion (without tests,
 with no special handling of trigger exceptions); removed basic translation of
 DataAccessException in IServer implementations (~200lines of code) -
 ServerExceptionTranlsatingAdvisor handles them

SVN: 22127
---
 .../web/client/ICommonClientService.java      |  19 +-
 .../web/client/ICommonClientServiceAsync.java |  25 +-
 .../client/web/client/application/Dict.java   |   6 +
 .../application/ui/deletion/DeletionGrid.java |  25 +-
 .../RevertDeletionConfirmationDialog.java     |  75 ++
 .../web/server/CommonClientService.java       |  24 +-
 .../openbis/generic/server/CommonServer.java  | 684 ++++++------------
 .../generic/server/CommonServerLogger.java    |   5 +
 .../openbis/generic/server/SearchHelper.java  |  28 +-
 .../ServerExceptionTranslatingAdvisor.java    |  10 +-
 .../generic/server/business/bo/ITrashBO.java  |   2 +
 .../generic/server/business/bo/TrashBO.java   |  15 +-
 .../server/dataaccess/db/DeletionDAO.java     |  30 +
 .../openbis/generic/shared/ICommonServer.java |  15 +
 .../generic/shared/basic/dto/Deletion.java    |  17 +-
 .../shared/translator/DeletionTranslator.java |   4 +
 .../cisd/openbis/public/common-dictionary.js  |   2 +
 .../shared/ICommonServer.java.expected        |  15 +
 18 files changed, 479 insertions(+), 522 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/RevertDeletionConfirmationDialog.java

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
index 237890b965a..1a5e4d67dd1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientService.java
@@ -348,13 +348,6 @@ public interface ICommonClientService extends IClientService
             DefaultResultSetConfig<String, TableModelRowWithObject<Project>> criteria)
             throws UserFailureException;
 
-    /**
-     * Returns a list of all deletions.
-     */
-    public TypedTableResultSet<Deletion> listDeletions(
-            DefaultResultSetConfig<String, TableModelRowWithObject<Deletion>> criteria)
-            throws UserFailureException;
-
     /**
      * Like {@link #prepareExportSamples(TableExportCriteria)}, but for projects.
      */
@@ -1089,4 +1082,16 @@ public interface ICommonClientService extends IClientService
     public EntityPropertyUpdatesResult updateProperties(EntityPropertyUpdates updates)
             throws UserFailureException;
 
+    /**
+     * Returns a list of all deletions.
+     */
+    public TypedTableResultSet<Deletion> listDeletions(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Deletion>> criteria)
+            throws UserFailureException;
+
+    /**
+     * Reverts specified deletions.
+     */
+    public void revertDeletions(List<TechId> deletionIds) throws UserFailureException;
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
index 045e0e58b99..ed07e57e708 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/ICommonClientServiceAsync.java
@@ -290,21 +290,11 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
             DefaultResultSetConfig<String, TableModelRowWithObject<Project>> criteria,
             final AsyncCallback<TypedTableResultSet<Project>> asyncCallback);
 
-    /** @see ICommonClientService#listDeletions(DefaultResultSetConfig) */
-    public void listDeletions(
-            DefaultResultSetConfig<String, TableModelRowWithObject<Deletion>> criteria,
-            final AsyncCallback<TypedTableResultSet<Deletion>> asyncCallback);
-
     /** @see ICommonClientService#prepareExportProjects(TableExportCriteria) */
     public void prepareExportProjects(
             TableExportCriteria<TableModelRowWithObject<Project>> exportCriteria,
             AsyncCallback<String> callback);
 
-    /** @see ICommonClientService#prepareExportDeletions(TableExportCriteria) */
-    public void prepareExportDeletions(
-            TableExportCriteria<TableModelRowWithObject<Deletion>> exportCriteria,
-            AsyncCallback<String> callback);
-
     /**
      * @see ICommonClientService#listVocabularies(boolean, boolean, DefaultResultSetConfig)
      */
@@ -983,4 +973,19 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
      */
     public void updateProperties(EntityPropertyUpdates entityPropertyUpdates,
             AsyncCallback<EntityPropertyUpdatesResult> callback);
+
+    /** @see ICommonClientService#listDeletions(DefaultResultSetConfig) */
+    public void listDeletions(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Deletion>> criteria,
+            final AsyncCallback<TypedTableResultSet<Deletion>> asyncCallback);
+
+    /** @see ICommonClientService#prepareExportDeletions(TableExportCriteria) */
+    public void prepareExportDeletions(
+            TableExportCriteria<TableModelRowWithObject<Deletion>> exportCriteria,
+            AsyncCallback<String> callback);
+
+    /**
+     * @see ICommonClientService#revertDeletions(List)
+     */
+    public void revertDeletions(List<TechId> deletionIds, AsyncCallback<Void> callback);
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
index c7f489f94b0..5fc114aecc3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/Dict.java
@@ -520,6 +520,12 @@ public abstract class Dict
 
     public static final String BUTTON_DELETE_PERMANENTLY = "button_delete_permanently";
 
+    public static final String REVERT_DELETIONS_CONFIRMATION_TITLE =
+            "revert_deletions_confirmation_title";
+
+    public static final String REVERT_DELETIONS_CONFIRMATION_MSG =
+            "revert_deletions_confirmation_msg";
+
     //
     // Sample Viewer
     //
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/DeletionGrid.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/DeletionGrid.java
index 0687e35f454..b71dcd557e8 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/DeletionGrid.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/DeletionGrid.java
@@ -16,9 +16,11 @@
 
 package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.deletion;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import com.extjs.gxt.ui.client.widget.Dialog;
 import com.extjs.gxt.ui.client.widget.MessageBox;
 import com.extjs.gxt.ui.client.widget.button.Button;
 import com.google.gwt.user.client.rpc.AsyncCallback;
@@ -33,6 +35,7 @@ import ch.systemsx.cisd.openbis.generic.client.web.client.application.model.Base
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.renderer.PersonRenderer;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.TypedTableGrid;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.ColumnDefsAndConfigs;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IBrowserGridActionInvoker;
 import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.grid.IDisposableComponent;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DefaultResultSetConfig;
 import ch.systemsx.cisd.openbis.generic.client.web.client.dto.DeletionGridColumnIDs;
@@ -72,18 +75,22 @@ public class DeletionGrid extends TypedTableGrid<Deletion>
     private void extendBottomToolbar()
     {
         addEntityOperationsLabel();
-
         Button revertButton =
-                createSelectedItemButton(
-                        viewContext.getMessage(Dict.BUTTON_REVERT_DELETION),
-                        new ISelectedEntityInvoker<BaseEntityModel<TableModelRowWithObject<Deletion>>>()
+                createSelectedItemsButton(viewContext.getMessage(Dict.BUTTON_REVERT_DELETION),
+                        new AbstractCreateDialogListener()
                             {
-                                public void invoke(
-                                        BaseEntityModel<TableModelRowWithObject<Deletion>> selectedItem,
-                                        boolean keyPressed)
+                                @Override
+                                protected Dialog createDialog(
+                                        List<TableModelRowWithObject<Deletion>> data,
+                                        IBrowserGridActionInvoker invoker)
                                 {
-                                    // TODO
-                                    MessageBox.info("Not implemented yet", "", null);
+                                    List<Deletion> deletions = new ArrayList<Deletion>();
+                                    for (TableModelRowWithObject<Deletion> row : data)
+                                    {
+                                        deletions.add(row.getObjectOrNull());
+                                    }
+                                    return new RevertDeletionConfirmationDialog(viewContext,
+                                            deletions, createRefreshCallback(invoker));
                                 }
                             });
         addButton(revertButton);
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/RevertDeletionConfirmationDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/RevertDeletionConfirmationDialog.java
new file mode 100644
index 00000000000..b7a215252ba
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/RevertDeletionConfirmationDialog.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2009 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.client.web.client.application.ui.deletion;
+
+import java.util.Collections;
+import java.util.List;
+
+import ch.systemsx.cisd.openbis.generic.client.web.client.ICommonClientServiceAsync;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.AbstractAsyncCallback;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.Dict;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.IViewContext;
+import ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.widget.AbstractDataConfirmationDialog;
+import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
+import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion;
+
+public final class RevertDeletionConfirmationDialog extends
+        AbstractDataConfirmationDialog<List<Deletion>>
+{
+    private static final int LABEL_WIDTH = 60;
+
+    private static final int FIELD_WIDTH = 180;
+
+    private final IViewContext<ICommonClientServiceAsync> viewContext;
+
+    private final AbstractAsyncCallback<Void> callback;
+
+    public RevertDeletionConfirmationDialog(IViewContext<ICommonClientServiceAsync> viewContext,
+            List<Deletion> deletions, AbstractAsyncCallback<Void> callback)
+    {
+        super(viewContext, deletions, viewContext
+                .getMessage(Dict.REVERT_DELETIONS_CONFIRMATION_TITLE));
+        this.viewContext = viewContext;
+        this.callback = callback;
+    }
+
+    public RevertDeletionConfirmationDialog(IViewContext<ICommonClientServiceAsync> viewContext,
+            Deletion deletion, AbstractAsyncCallback<Void> callback)
+    {
+        this(viewContext, Collections.singletonList(deletion), callback);
+    }
+
+    @Override
+    protected void executeConfirmedAction()
+    {
+        viewContext.getCommonService().revertDeletions(TechId.createList(data), callback);
+    }
+
+    @Override
+    protected String createMessage()
+    {
+        return viewContext.getMessage(Dict.REVERT_DELETIONS_CONFIRMATION_MSG, data.size());
+    }
+
+    @Override
+    protected void extendForm()
+    {
+        formPanel.setLabelWidth(LABEL_WIDTH);
+        formPanel.setFieldWidth(FIELD_WIDTH);
+    }
+
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
index 12e5b0036f2..84e179ae71d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/CommonClientService.java
@@ -669,15 +669,6 @@ public final class CommonClientService extends AbstractClientService implements
         return listEntities(projectsProvider, criteria);
     }
 
-    public TypedTableResultSet<Deletion> listDeletions(
-            DefaultResultSetConfig<String, TableModelRowWithObject<Deletion>> criteria)
-            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
-    {
-        DeletionsProvider deletionsProvider =
-                new DeletionsProvider(commonServer, getSessionToken());
-        return listEntities(deletionsProvider, criteria);
-    }
-
     public TypedTableResultSet<Vocabulary> listVocabularies(boolean withTerms,
             boolean excludeInternal,
             DefaultResultSetConfig<String, TableModelRowWithObject<Vocabulary>> criteria)
@@ -2214,4 +2205,19 @@ public final class CommonClientService extends AbstractClientService implements
         }
         return result;
     }
+
+    public TypedTableResultSet<Deletion> listDeletions(
+            DefaultResultSetConfig<String, TableModelRowWithObject<Deletion>> criteria)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        DeletionsProvider deletionsProvider =
+                new DeletionsProvider(commonServer, getSessionToken());
+        return listEntities(deletionsProvider, criteria);
+    }
+
+    public void revertDeletions(List<TechId> deletionIds)
+            throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
+    {
+        commonServer.revertDeletions(getSessionToken(), deletionIds);
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
index 47c0c90045a..bf90fb63a04 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServer.java
@@ -268,11 +268,6 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         return businessObjectFactory;
     }
 
-    static UserFailureException createUserFailureException(final DataAccessException ex)
-    {
-        return new UserFailureException(ex.getMostSpecificCause().getMessage(), ex);
-    }
-
     //
     // IInvocationLoggerFactory
     //
@@ -309,14 +304,6 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     // IGenericServer
     //
 
-    public final List<Deletion> listDeletions(final String sessionToken)
-    {
-        checkSession(sessionToken);
-        final List<DeletionPE> deletions = getDAOFactory().getDeletionDAO().listAllEntities();
-        Collections.sort(deletions);
-        return DeletionTranslator.translate(deletions);
-    }
-
     public final List<Space> listSpaces(final String sessionToken,
             final DatabaseInstanceIdentifier identifier)
     {
@@ -579,21 +566,14 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     {
         checkSession(sessionToken);
         final List<MatchingEntity> list = new ArrayList<MatchingEntity>();
-        try
-        {
-            for (final SearchableEntity searchableEntity : searchableEntities)
-            {
-                HibernateSearchDataProvider dataProvider =
-                        new HibernateSearchDataProvider(getDAOFactory());
-                List<MatchingEntity> entities =
-                        getDAOFactory().getHibernateSearchDAO().searchEntitiesByTerm(
-                                searchableEntity, queryText, dataProvider, useWildcardSearchMode,
-                                list.size(), maxSize);
-                list.addAll(entities);
-            }
-        } catch (final DataAccessException ex)
+        for (final SearchableEntity searchableEntity : searchableEntities)
         {
-            throw createUserFailureException(ex);
+            HibernateSearchDataProvider dataProvider =
+                    new HibernateSearchDataProvider(getDAOFactory());
+            List<MatchingEntity> entities =
+                    getDAOFactory().getHibernateSearchDAO().searchEntitiesByTerm(searchableEntity,
+                            queryText, dataProvider, useWildcardSearchMode, list.size(), maxSize);
+            list.addAll(entities);
         }
         return list;
     }
@@ -966,21 +946,15 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             DataSetRelatedEntities relatedEntities)
     {
         final Session session = getSession(sessionToken);
-        try
+        final Set<DataPE> resultSet = new LinkedHashSet<DataPE>();
+        // TODO 2009-08-17, Piotr Buczek: [LMS-1149] optimize performance
+        addRelatedDataSets(resultSet, relatedEntities.getEntities());
+        final List<ExternalData> list = new ArrayList<ExternalData>(resultSet.size());
+        for (final DataPE hit : resultSet)
         {
-            final Set<DataPE> resultSet = new LinkedHashSet<DataPE>();
-            // TODO 2009-08-17, Piotr Buczek: [LMS-1149] optimize performance
-            addRelatedDataSets(resultSet, relatedEntities.getEntities());
-            final List<ExternalData> list = new ArrayList<ExternalData>(resultSet.size());
-            for (final DataPE hit : resultSet)
-            {
-                list.add(DataSetTranslator.translate(hit, session.getBaseIndexURL(), false));
-            }
-            return list;
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
+            list.add(DataSetTranslator.translate(hit, session.getBaseIndexURL(), false));
         }
+        return list;
     }
 
     private void addRelatedDataSets(final Set<DataPE> resultSet,
@@ -1021,15 +995,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     public void registerSampleType(String sessionToken, SampleType entityType)
     {
         final Session session = getSession(sessionToken);
-        try
-        {
-            IEntityTypeBO entityTypeBO = businessObjectFactory.createEntityTypeBO(session);
-            entityTypeBO.define(entityType);
-            entityTypeBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IEntityTypeBO entityTypeBO = businessObjectFactory.createEntityTypeBO(session);
+        entityTypeBO.define(entityType);
+        entityTypeBO.save();
     }
 
     public void updateSampleType(String sessionToken, EntityType entityType)
@@ -1040,15 +1008,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     public void registerMaterialType(String sessionToken, MaterialType entityType)
     {
         final Session session = getSession(sessionToken);
-        try
-        {
-            IEntityTypeBO entityTypeBO = businessObjectFactory.createEntityTypeBO(session);
-            entityTypeBO.define(entityType);
-            entityTypeBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IEntityTypeBO entityTypeBO = businessObjectFactory.createEntityTypeBO(session);
+        entityTypeBO.define(entityType);
+        entityTypeBO.save();
     }
 
     public void updateMaterialType(String sessionToken, EntityType entityType)
@@ -1059,15 +1021,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     public void registerExperimentType(String sessionToken, ExperimentType entityType)
     {
         final Session session = getSession(sessionToken);
-        try
-        {
-            IEntityTypeBO entityTypeBO = businessObjectFactory.createEntityTypeBO(session);
-            entityTypeBO.define(entityType);
-            entityTypeBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IEntityTypeBO entityTypeBO = businessObjectFactory.createEntityTypeBO(session);
+        entityTypeBO.define(entityType);
+        entityTypeBO.save();
     }
 
     public void updateExperimentType(String sessionToken, EntityType entityType)
@@ -1094,15 +1050,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     public void registerDataSetType(String sessionToken, DataSetType entityType)
     {
         final Session session = getSession(sessionToken);
-        try
-        {
-            IEntityTypeBO entityTypeBO = businessObjectFactory.createEntityTypeBO(session);
-            entityTypeBO.define(entityType);
-            entityTypeBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IEntityTypeBO entityTypeBO = businessObjectFactory.createEntityTypeBO(session);
+        entityTypeBO.define(entityType);
+        entityTypeBO.save();
     }
 
     public void updateDataSetType(String sessionToken, EntityType entityType)
@@ -1113,19 +1063,12 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     private void updateEntityType(String sessionToken, EntityKind entityKind, EntityType entityType)
     {
         checkSession(sessionToken);
-        try
-        {
-            IEntityTypeDAO entityTypeDAO =
-                    getDAOFactory().getEntityTypeDAO(DtoConverters.convertEntityKind(entityKind));
-            EntityTypePE entityTypePE =
-                    entityTypeDAO.tryToFindEntityTypeByCode(entityType.getCode());
-            entityTypePE.setDescription(entityType.getDescription());
-            updateSpecificEntityTypeProperties(entityKind, entityTypePE, entityType);
-            entityTypeDAO.createOrUpdateEntityType(entityTypePE);
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IEntityTypeDAO entityTypeDAO =
+                getDAOFactory().getEntityTypeDAO(DtoConverters.convertEntityKind(entityKind));
+        EntityTypePE entityTypePE = entityTypeDAO.tryToFindEntityTypeByCode(entityType.getCode());
+        entityTypePE.setDescription(entityType.getDescription());
+        updateSpecificEntityTypeProperties(entityKind, entityTypePE, entityType);
+        entityTypeDAO.createOrUpdateEntityType(entityTypePE);
     }
 
     private void updateSpecificEntityTypeProperties(EntityKind entityKind,
@@ -1155,34 +1098,28 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             DeletionType deletionType)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IDataSetTable dataSetTable = businessObjectFactory.createDataSetTable(session);
-            // TODO 2011-06-21, Piotr Buczek: loading less for deletion would probably be faster
-            dataSetTable.loadByDataSetCodes(dataSetCodes, false, false);
-            List<DataPE> dataSets = dataSetTable.getDataSets();
-            Map<DataSetTypePE, List<DataPE>> groupedDataSets =
-                    new LinkedHashMap<DataSetTypePE, List<DataPE>>();
-            for (DataPE dataSet : dataSets)
-            {
-                DataSetTypePE dataSetType = dataSet.getDataSetType();
-                List<DataPE> list = groupedDataSets.get(dataSetType);
-                if (list == null)
-                {
-                    list = new ArrayList<DataPE>();
-                    groupedDataSets.put(dataSetType, list);
-                }
-                list.add(dataSet);
-            }
-            for (Map.Entry<DataSetTypePE, List<DataPE>> entry : groupedDataSets.entrySet())
+        IDataSetTable dataSetTable = businessObjectFactory.createDataSetTable(session);
+        // TODO 2011-06-21, Piotr Buczek: loading less for deletion would probably be faster
+        dataSetTable.loadByDataSetCodes(dataSetCodes, false, false);
+        List<DataPE> dataSets = dataSetTable.getDataSets();
+        Map<DataSetTypePE, List<DataPE>> groupedDataSets =
+                new LinkedHashMap<DataSetTypePE, List<DataPE>>();
+        for (DataPE dataSet : dataSets)
+        {
+            DataSetTypePE dataSetType = dataSet.getDataSetType();
+            List<DataPE> list = groupedDataSets.get(dataSetType);
+            if (list == null)
             {
-                DataSetTypePE dataSetType = entry.getKey();
-                IDataSetTypeSlaveServerPlugin plugin = getDataSetTypeSlaveServerPlugin(dataSetType);
-                plugin.deleteDataSets(session, entry.getValue(), reason, deletionType);
+                list = new ArrayList<DataPE>();
+                groupedDataSets.put(dataSetType, list);
             }
-        } catch (final DataAccessException ex)
+            list.add(dataSet);
+        }
+        for (Map.Entry<DataSetTypePE, List<DataPE>> entry : groupedDataSets.entrySet())
         {
-            throw createUserFailureException(ex);
+            DataSetTypePE dataSetType = entry.getKey();
+            IDataSetTypeSlaveServerPlugin plugin = getDataSetTypeSlaveServerPlugin(dataSetType);
+            plugin.deleteDataSets(session, entry.getValue(), reason, deletionType);
         }
     }
 
@@ -1190,23 +1127,17 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             DeletionType deletionType)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            switch (deletionType)
-            {
-                case PERMANENT:
-                    ISampleTable sampleTableBO = businessObjectFactory.createSampleTable(session);
-                    sampleTableBO.deleteByTechIds(sampleIds, reason);
-                    break;
-                case TRASH:
-                    ITrashBO trashBO = businessObjectFactory.createTrashBO(session);
-                    trashBO.createDeletion(reason);
-                    trashBO.trashSamples(sampleIds);
-                    break;
-            }
-        } catch (final DataAccessException ex)
+        switch (deletionType)
         {
-            throw createUserFailureException(ex);
+            case PERMANENT:
+                ISampleTable sampleTableBO = businessObjectFactory.createSampleTable(session);
+                sampleTableBO.deleteByTechIds(sampleIds, reason);
+                break;
+            case TRASH:
+                ITrashBO trashBO = businessObjectFactory.createTrashBO(session);
+                trashBO.createDeletion(reason);
+                trashBO.trashSamples(sampleIds);
+                break;
         }
     }
 
@@ -1214,55 +1145,37 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             DeletionType deletionType)
     {
         Session session = getSession(sessionToken);
-        try
+        IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
+        switch (deletionType)
         {
-            IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
-            switch (deletionType)
-            {
-                case PERMANENT:
-                    experimentBO.deleteByTechIds(experimentIds, reason);
-                    break;
-                case TRASH:
-                    ITrashBO trashBO = businessObjectFactory.createTrashBO(session);
-                    trashBO.createDeletion(reason);
-                    trashBO.trashExperiments(experimentIds);
-                    break;
-            }
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
+            case PERMANENT:
+                experimentBO.deleteByTechIds(experimentIds, reason);
+                break;
+            case TRASH:
+                ITrashBO trashBO = businessObjectFactory.createTrashBO(session);
+                trashBO.createDeletion(reason);
+                trashBO.trashExperiments(experimentIds);
+                break;
         }
     }
 
     public void deleteVocabularies(String sessionToken, List<TechId> vocabularyIds, String reason)
     {
         Session session = getSession(sessionToken);
-        try
+        IVocabularyBO vocabularyBO = businessObjectFactory.createVocabularyBO(session);
+        for (TechId id : vocabularyIds)
         {
-            IVocabularyBO vocabularyBO = businessObjectFactory.createVocabularyBO(session);
-            for (TechId id : vocabularyIds)
-            {
-                vocabularyBO.deleteByTechId(id, reason);
-            }
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
+            vocabularyBO.deleteByTechId(id, reason);
         }
     }
 
     public void deletePropertyTypes(String sessionToken, List<TechId> propertyTypeIds, String reason)
     {
         Session session = getSession(sessionToken);
-        try
+        IPropertyTypeBO propertyTypeBO = businessObjectFactory.createPropertyTypeBO(session);
+        for (TechId id : propertyTypeIds)
         {
-            IPropertyTypeBO propertyTypeBO = businessObjectFactory.createPropertyTypeBO(session);
-            for (TechId id : propertyTypeIds)
-            {
-                propertyTypeBO.deleteByTechId(id, reason);
-            }
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
+            propertyTypeBO.deleteByTechId(id, reason);
         }
     }
 
@@ -1270,48 +1183,30 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     public void deleteProjects(String sessionToken, List<TechId> projectIds, String reason)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IProjectBO projectBO = businessObjectFactory.createProjectBO(session);
-            for (TechId id : projectIds)
-            {
-                projectBO.deleteByTechId(id, reason);
-            }
-        } catch (final DataAccessException ex)
+        IProjectBO projectBO = businessObjectFactory.createProjectBO(session);
+        for (TechId id : projectIds)
         {
-            throw createUserFailureException(ex);
+            projectBO.deleteByTechId(id, reason);
         }
     }
 
     public void deleteSpaces(String sessionToken, List<TechId> groupIds, String reason)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IGroupBO groupBO = businessObjectFactory.createGroupBO(session);
-            for (TechId id : groupIds)
-            {
-                groupBO.deleteByTechId(id, reason);
-            }
-        } catch (final DataAccessException ex)
+        IGroupBO groupBO = businessObjectFactory.createGroupBO(session);
+        for (TechId id : groupIds)
         {
-            throw createUserFailureException(ex);
+            groupBO.deleteByTechId(id, reason);
         }
     }
 
     public void deleteScripts(String sessionToken, List<TechId> scriptIds)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IScriptBO scriptBO = businessObjectFactory.createScriptBO(session);
-            for (TechId id : scriptIds)
-            {
-                scriptBO.deleteByTechId(id);
-            }
-        } catch (final DataAccessException ex)
+        IScriptBO scriptBO = businessObjectFactory.createScriptBO(session);
+        for (TechId id : scriptIds)
         {
-            throw createUserFailureException(ex);
+            scriptBO.deleteByTechId(id);
         }
     }
 
@@ -1319,78 +1214,48 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             List<String> fileNames, String reason)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
-            experimentBO.loadDataByTechId(experimentId);
-            deleteHolderAttachments(session, experimentBO.getExperiment(), fileNames, reason);
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
+        experimentBO.loadDataByTechId(experimentId);
+        deleteHolderAttachments(session, experimentBO.getExperiment(), fileNames, reason);
     }
 
     public void updateExperimentAttachments(String sessionToken, TechId experimentId,
             Attachment attachment)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
-            experimentBO.loadDataByTechId(experimentId);
-            IAttachmentBO attachmentBO = businessObjectFactory.createAttachmentBO(session);
-            attachmentBO.updateAttachment(experimentBO.getExperiment(), attachment);
-            attachmentBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
+        experimentBO.loadDataByTechId(experimentId);
+        IAttachmentBO attachmentBO = businessObjectFactory.createAttachmentBO(session);
+        attachmentBO.updateAttachment(experimentBO.getExperiment(), attachment);
+        attachmentBO.save();
     }
 
     public void addExperimentAttachment(String sessionToken, TechId experimentId,
             NewAttachment attachment)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IExperimentBO bo = businessObjectFactory.createExperimentBO(session);
-            bo.loadDataByTechId(experimentId);
-            bo.addAttachment(AttachmentTranslator.translate(attachment));
-            bo.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IExperimentBO bo = businessObjectFactory.createExperimentBO(session);
+        bo.loadDataByTechId(experimentId);
+        bo.addAttachment(AttachmentTranslator.translate(attachment));
+        bo.save();
     }
 
     public void deleteSampleAttachments(String sessionToken, TechId sampleId,
             List<String> fileNames, String reason)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
-            sampleBO.loadDataByTechId(sampleId);
-            deleteHolderAttachments(session, sampleBO.getSample(), fileNames, reason);
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
+        sampleBO.loadDataByTechId(sampleId);
+        deleteHolderAttachments(session, sampleBO.getSample(), fileNames, reason);
     }
 
     public void deleteProjectAttachments(String sessionToken, TechId projectId,
             List<String> fileNames, String reason)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IProjectBO projectBO = businessObjectFactory.createProjectBO(session);
-            projectBO.loadDataByTechId(projectId);
-            deleteHolderAttachments(session, projectBO.getProject(), fileNames, reason);
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IProjectBO projectBO = businessObjectFactory.createProjectBO(session);
+        projectBO.loadDataByTechId(projectId);
+        deleteHolderAttachments(session, projectBO.getProject(), fileNames, reason);
     }
 
     private void deleteHolderAttachments(Session session, AttachmentHolderPE holder,
@@ -1403,49 +1268,29 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     public List<Attachment> listExperimentAttachments(String sessionToken, TechId experimentId)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
-            experimentBO.loadDataByTechId(experimentId);
-            return AttachmentTranslator.translate(
-                    listHolderAttachments(session, experimentBO.getExperiment()),
-                    session.getBaseIndexURL());
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
+        experimentBO.loadDataByTechId(experimentId);
+        return AttachmentTranslator.translate(
+                listHolderAttachments(session, experimentBO.getExperiment()),
+                session.getBaseIndexURL());
     }
 
     public List<Attachment> listSampleAttachments(String sessionToken, TechId sampleId)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
-            sampleBO.loadDataByTechId(sampleId);
-            return AttachmentTranslator
-                    .translate(listHolderAttachments(session, sampleBO.getSample()),
-                            session.getBaseIndexURL());
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
+        sampleBO.loadDataByTechId(sampleId);
+        return AttachmentTranslator.translate(listHolderAttachments(session, sampleBO.getSample()),
+                session.getBaseIndexURL());
     }
 
     public List<Attachment> listProjectAttachments(String sessionToken, TechId projectId)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IProjectBO projectBO = businessObjectFactory.createProjectBO(session);
-            projectBO.loadDataByTechId(projectId);
-            return AttachmentTranslator.translate(
-                    listHolderAttachments(session, projectBO.getProject()),
-                    session.getBaseIndexURL());
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IProjectBO projectBO = businessObjectFactory.createProjectBO(session);
+        projectBO.loadDataByTechId(projectId);
+        return AttachmentTranslator.translate(
+                listHolderAttachments(session, projectBO.getProject()), session.getBaseIndexURL());
     }
 
     private List<AttachmentPE> listHolderAttachments(Session session, AttachmentHolderPE holder)
@@ -1457,15 +1302,9 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             DataSetUploadContext uploadContext)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IDataSetTable dataSetTable = businessObjectFactory.createDataSetTable(session);
-            dataSetTable.loadByDataSetCodes(dataSetCodes, true, false);
-            return dataSetTable.uploadLoadedDataSetsToCIFEX(uploadContext);
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IDataSetTable dataSetTable = businessObjectFactory.createDataSetTable(session);
+        dataSetTable.loadByDataSetCodes(dataSetCodes, true, false);
+        return dataSetTable.uploadLoadedDataSetsToCIFEX(uploadContext);
     }
 
     public List<VocabularyTermWithStats> listVocabularyTermsWithStatistics(String sessionToken,
@@ -1923,16 +1762,10 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     public void updateFileFormatType(String sessionToken, AbstractType type)
     {
         checkSession(sessionToken);
-        try
-        {
-            IFileFormatTypeDAO dao = getDAOFactory().getFileFormatTypeDAO();
-            FileFormatTypePE typePE = dao.tryToFindFileFormatTypeByCode(type.getCode());
-            typePE.setDescription(type.getDescription());
-            dao.createOrUpdate(typePE);
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IFileFormatTypeDAO dao = getDAOFactory().getFileFormatTypeDAO();
+        FileFormatTypePE typePE = dao.tryToFindFileFormatTypeByCode(type.getCode());
+        typePE.setDescription(type.getDescription());
+        dao.createOrUpdate(typePE);
 
     }
 
@@ -1940,65 +1773,40 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             Attachment attachment)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IProjectBO bo = businessObjectFactory.createProjectBO(session);
-            bo.loadDataByTechId(projectId);
-            IAttachmentBO attachmentBO = businessObjectFactory.createAttachmentBO(session);
-            attachmentBO.updateAttachment(bo.getProject(), attachment);
-            attachmentBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
-
+        IProjectBO bo = businessObjectFactory.createProjectBO(session);
+        bo.loadDataByTechId(projectId);
+        IAttachmentBO attachmentBO = businessObjectFactory.createAttachmentBO(session);
+        attachmentBO.updateAttachment(bo.getProject(), attachment);
+        attachmentBO.save();
     }
 
     public void addProjectAttachments(String sessionToken, TechId projectId,
             NewAttachment attachment)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IProjectBO bo = businessObjectFactory.createProjectBO(session);
-            bo.loadDataByTechId(projectId);
-            bo.addAttachment(AttachmentTranslator.translate(attachment));
-            bo.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IProjectBO bo = businessObjectFactory.createProjectBO(session);
+        bo.loadDataByTechId(projectId);
+        bo.addAttachment(AttachmentTranslator.translate(attachment));
+        bo.save();
     }
 
     public void updateSampleAttachments(String sessionToken, TechId sampleId, Attachment attachment)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            ISampleBO bo = businessObjectFactory.createSampleBO(session);
-            bo.loadDataByTechId(sampleId);
-            IAttachmentBO attachmentBO = businessObjectFactory.createAttachmentBO(session);
-            attachmentBO.updateAttachment(bo.getSample(), attachment);
-            attachmentBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        ISampleBO bo = businessObjectFactory.createSampleBO(session);
+        bo.loadDataByTechId(sampleId);
+        IAttachmentBO attachmentBO = businessObjectFactory.createAttachmentBO(session);
+        attachmentBO.updateAttachment(bo.getSample(), attachment);
+        attachmentBO.save();
     }
 
     public void addSampleAttachments(String sessionToken, TechId sampleId, NewAttachment attachment)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            ISampleBO bo = businessObjectFactory.createSampleBO(session);
-            bo.loadDataByTechId(sampleId);
-            bo.addAttachment(AttachmentTranslator.translate(attachment));
-            bo.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        ISampleBO bo = businessObjectFactory.createSampleBO(session);
+        bo.loadDataByTechId(sampleId);
+        bo.addAttachment(AttachmentTranslator.translate(attachment));
+        bo.save();
     }
 
     public List<DatastoreServiceDescription> listDataStoreServices(String sessionToken,
@@ -2053,45 +1861,27 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             NewAuthorizationGroup newAuthorizationGroup)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IAuthorizationGroupBO bo = businessObjectFactory.createAuthorizationGroupBO(session);
-            bo.define(newAuthorizationGroup);
-            bo.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IAuthorizationGroupBO bo = businessObjectFactory.createAuthorizationGroupBO(session);
+        bo.define(newAuthorizationGroup);
+        bo.save();
     }
 
     public void registerScript(String sessionToken, Script script)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IScriptBO bo = businessObjectFactory.createScriptBO(session);
-            bo.define(script);
-            bo.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        IScriptBO bo = businessObjectFactory.createScriptBO(session);
+        bo.define(script);
+        bo.save();
     }
 
     public void deleteAuthorizationGroups(String sessionToken, List<TechId> groupIds, String reason)
     {
         Session session = getSession(sessionToken);
-        try
+        IAuthorizationGroupBO authGroupBO =
+                businessObjectFactory.createAuthorizationGroupBO(session);
+        for (TechId id : groupIds)
         {
-            IAuthorizationGroupBO authGroupBO =
-                    businessObjectFactory.createAuthorizationGroupBO(session);
-            for (TechId id : groupIds)
-            {
-                authGroupBO.deleteByTechId(id, reason);
-            }
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
+            authGroupBO.deleteByTechId(id, reason);
         }
     }
 
@@ -2190,43 +1980,25 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
 
     private void registerFilterOrColumn(NewColumnOrFilter filter, IGridCustomFilterOrColumnBO bo)
     {
-        try
-        {
-            bo.define(filter);
-            bo.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        bo.define(filter);
+        bo.save();
     }
 
     private void deleteFiltersOrColumns(List<TechId> filterIds, IGridCustomFilterOrColumnBO bo)
     {
-        try
-        {
-            for (TechId id : filterIds)
-            {
-                bo.deleteByTechId(id);
-            }
-        } catch (final DataAccessException ex)
+        for (TechId id : filterIds)
         {
-            throw createUserFailureException(ex);
+            bo.deleteByTechId(id);
         }
     }
 
     public List<GridCustomFilter> listFilters(String sessionToken, String gridId)
     {
         checkSession(sessionToken);
-        try
-        {
-            List<GridCustomFilterPE> filters =
-                    getDAOFactory().getGridCustomFilterDAO().listFilters(gridId);
-            Collections.sort(filters);
-            return GridCustomFilterTranslator.translate(filters);
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        List<GridCustomFilterPE> filters =
+                getDAOFactory().getGridCustomFilterDAO().listFilters(gridId);
+        Collections.sort(filters);
+        return GridCustomFilterTranslator.translate(filters);
     }
 
     public void registerFilter(String sessionToken, NewColumnOrFilter filter)
@@ -2394,101 +2166,76 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
             IManagedProperty managedProperty, IManagedUiAction updateAction)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
-            experimentBO.loadDataByTechId(experimentId);
+        IExperimentBO experimentBO = businessObjectFactory.createExperimentBO(session);
+        experimentBO.loadDataByTechId(experimentId);
 
-            // Evaluate the script
-            experimentBO.enrichWithProperties();
-            Set<? extends EntityPropertyPE> properties =
-                    experimentBO.getExperiment().getProperties();
-            ManagedPropertyEvaluator evaluator =
-                    tryManagedPropertyEvaluator(managedProperty, properties);
-            extendWithPerson(updateAction, session.tryGetPerson());
-            evaluator.updateFromUI(managedProperty, updateAction);
+        // Evaluate the script
+        experimentBO.enrichWithProperties();
+        Set<? extends EntityPropertyPE> properties = experimentBO.getExperiment().getProperties();
+        ManagedPropertyEvaluator evaluator =
+                tryManagedPropertyEvaluator(managedProperty, properties);
+        extendWithPerson(updateAction, session.tryGetPerson());
+        evaluator.updateFromUI(managedProperty, updateAction);
 
-            experimentBO.updateManagedProperty(managedProperty);
-            experimentBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        experimentBO.updateManagedProperty(managedProperty);
+        experimentBO.save();
     }
 
     public void updateManagedPropertyOnSample(String sessionToken, TechId experimentId,
             IManagedProperty managedProperty, IManagedUiAction updateAction)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
-            sampleBO.loadDataByTechId(experimentId);
-
-            // Evaluate the script
-            sampleBO.enrichWithProperties();
-            Set<? extends EntityPropertyPE> properties = sampleBO.getSample().getProperties();
-            ManagedPropertyEvaluator evaluator =
-                    tryManagedPropertyEvaluator(managedProperty, properties);
-            extendWithPerson(updateAction, session.tryGetPerson());
-            evaluator.updateFromUI(managedProperty, updateAction);
-
-            sampleBO.updateManagedProperty(managedProperty);
-            sampleBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        ISampleBO sampleBO = businessObjectFactory.createSampleBO(session);
+        sampleBO.loadDataByTechId(experimentId);
+
+        // Evaluate the script
+        sampleBO.enrichWithProperties();
+        Set<? extends EntityPropertyPE> properties = sampleBO.getSample().getProperties();
+        ManagedPropertyEvaluator evaluator =
+                tryManagedPropertyEvaluator(managedProperty, properties);
+        extendWithPerson(updateAction, session.tryGetPerson());
+        evaluator.updateFromUI(managedProperty, updateAction);
+
+        sampleBO.updateManagedProperty(managedProperty);
+        sampleBO.save();
     }
 
     public void updateManagedPropertyOnDataSet(String sessionToken, TechId experimentId,
             IManagedProperty managedProperty, IManagedUiAction updateAction)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IDataBO dataSetBO = businessObjectFactory.createDataBO(session);
-            dataSetBO.loadDataByTechId(experimentId);
+        IDataBO dataSetBO = businessObjectFactory.createDataBO(session);
+        dataSetBO.loadDataByTechId(experimentId);
 
-            // Evaluate the script
-            dataSetBO.enrichWithProperties();
-            Set<? extends EntityPropertyPE> properties = dataSetBO.getData().getProperties();
-            ManagedPropertyEvaluator evaluator =
-                    tryManagedPropertyEvaluator(managedProperty, properties);
-            extendWithPerson(updateAction, session.tryGetPerson());
-            evaluator.updateFromUI(managedProperty, updateAction);
+        // Evaluate the script
+        dataSetBO.enrichWithProperties();
+        Set<? extends EntityPropertyPE> properties = dataSetBO.getData().getProperties();
+        ManagedPropertyEvaluator evaluator =
+                tryManagedPropertyEvaluator(managedProperty, properties);
+        extendWithPerson(updateAction, session.tryGetPerson());
+        evaluator.updateFromUI(managedProperty, updateAction);
 
-            dataSetBO.updateManagedProperty(managedProperty);
-            dataSetBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        dataSetBO.updateManagedProperty(managedProperty);
+        dataSetBO.save();
     }
 
     public void updateManagedPropertyOnMaterial(String sessionToken, TechId experimentId,
             IManagedProperty managedProperty, IManagedUiAction updateAction)
     {
         Session session = getSession(sessionToken);
-        try
-        {
-            IMaterialBO materialBO = businessObjectFactory.createMaterialBO(session);
-            materialBO.loadDataByTechId(experimentId);
+        IMaterialBO materialBO = businessObjectFactory.createMaterialBO(session);
+        materialBO.loadDataByTechId(experimentId);
 
-            // Evaluate the script
-            materialBO.enrichWithProperties();
-            Set<? extends EntityPropertyPE> properties = materialBO.getMaterial().getProperties();
-            ManagedPropertyEvaluator evaluator =
-                    tryManagedPropertyEvaluator(managedProperty, properties);
-            extendWithPerson(updateAction, session.tryGetPerson());
-            evaluator.updateFromUI(managedProperty, updateAction);
+        // Evaluate the script
+        materialBO.enrichWithProperties();
+        Set<? extends EntityPropertyPE> properties = materialBO.getMaterial().getProperties();
+        ManagedPropertyEvaluator evaluator =
+                tryManagedPropertyEvaluator(managedProperty, properties);
+        extendWithPerson(updateAction, session.tryGetPerson());
+        evaluator.updateFromUI(managedProperty, updateAction);
 
-            materialBO.updateManagedProperty(managedProperty);
-            materialBO.save();
-        } catch (final DataAccessException ex)
-        {
-            throw createUserFailureException(ex);
-        }
+        materialBO.updateManagedProperty(managedProperty);
+        materialBO.save();
     }
 
     private static void extendWithPerson(IManagedUiAction updateAction, PersonPE personOrNull)
@@ -2638,6 +2385,25 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         return properties;
     }
 
+    public final List<Deletion> listDeletions(final String sessionToken)
+    {
+        checkSession(sessionToken);
+        final List<DeletionPE> deletions = getDAOFactory().getDeletionDAO().listAllEntities();
+        Collections.sort(deletions);
+        return DeletionTranslator.translate(deletions);
+    }
+
+    public final void revertDeletions(final String sessionToken, final List<TechId> deletionIds)
+    {
+        final Session session = getSession(sessionToken);
+
+        final ITrashBO trashBO = getBusinessObjectFactory().createTrashBO(session);
+        for (TechId deletionId : deletionIds)
+        {
+            trashBO.revertDeletion(deletionId);
+        }
+    }
+
     private static UserFailureException wrapExceptionWithEntityIdentifier(
             UserFailureException exception, IEntityInformationHolderWithIdentifier entity)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
index dda316c338b..5a809f00862 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/CommonServerLogger.java
@@ -1131,4 +1131,9 @@ final class CommonServerLogger extends AbstractServerLogger implements ICommonSe
         logAccess(sessionToken, "listDeletions");
         return null;
     }
+
+    public void revertDeletions(String sessionToken, List<TechId> deletionIds)
+    {
+        logTracking(sessionToken, "revertDeletions", "ID(%s)", deletionIds);
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SearchHelper.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SearchHelper.java
index ea6ef9b6dd1..4ba156110c9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SearchHelper.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/SearchHelper.java
@@ -18,8 +18,6 @@ package ch.systemsx.cisd.openbis.generic.server;
 
 import java.util.List;
 
-import org.springframework.dao.DataAccessException;
-
 import ch.systemsx.cisd.openbis.generic.server.business.bo.ICommonBusinessObjectFactory;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.datasetlister.IDatasetLister;
 import ch.systemsx.cisd.openbis.generic.server.business.bo.samplelister.ISampleLister;
@@ -56,28 +54,16 @@ class SearchHelper
 
     public List<Sample> searchForSamples(DetailedSearchCriteria criteria)
     {
-        try
-        {
-            final ISampleLister sampleLister = businessObjectFactory.createSampleLister(session);
-            final IHibernateSearchDAO searchDAO = daoFactory.getHibernateSearchDAO();
-            return new SampleSearchManager(searchDAO, sampleLister).searchForSamples(criteria);
-        } catch (final DataAccessException ex)
-        {
-            throw CommonServer.createUserFailureException(ex);
-        }
+        final ISampleLister sampleLister = businessObjectFactory.createSampleLister(session);
+        final IHibernateSearchDAO searchDAO = daoFactory.getHibernateSearchDAO();
+        return new SampleSearchManager(searchDAO, sampleLister).searchForSamples(criteria);
     }
 
     public List<ExternalData> searchForDataSets(DetailedSearchCriteria detailedSearchCriteria)
     {
-        try
-        {
-            IHibernateSearchDAO searchDAO = daoFactory.getHibernateSearchDAO();
-            IDatasetLister dataSetLister = businessObjectFactory.createDatasetLister(session);
-            return new DataSetSearchManager(searchDAO, dataSetLister)
-                    .searchForDataSets(detailedSearchCriteria);
-        } catch (DataAccessException ex)
-        {
-            throw CommonServer.createUserFailureException(ex);
-        }
+        IHibernateSearchDAO searchDAO = daoFactory.getHibernateSearchDAO();
+        IDatasetLister dataSetLister = businessObjectFactory.createDatasetLister(session);
+        return new DataSetSearchManager(searchDAO, dataSetLister)
+                .searchForDataSets(detailedSearchCriteria);
     }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServerExceptionTranslatingAdvisor.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServerExceptionTranslatingAdvisor.java
index 870c819d29a..bc9ec12087a 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServerExceptionTranslatingAdvisor.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/ServerExceptionTranslatingAdvisor.java
@@ -24,6 +24,7 @@ import org.springframework.aop.Pointcut;
 import org.springframework.aop.support.DefaultPointcutAdvisor;
 import org.springframework.aop.support.RootClassFilter;
 import org.springframework.core.NestedRuntimeException;
+import org.springframework.dao.DataAccessException;
 import org.springframework.transaction.TransactionSystemException;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -32,8 +33,8 @@ import ch.systemsx.cisd.openbis.generic.shared.IServer;
 
 /**
  * Translates deeply nested exceptions thrown on server side e.g. by Spring (like
- * {@link TransactionSystemException}) into {UserFailureException} with message taken from the root
- * exception cause.
+ * {@link TransactionSystemException} or {@link DataAccessException}) into {UserFailureException}
+ * with message taken from the root exception cause.
  * <p>
  * The most important reason why this advisor was introduced was to translate exceptions that happen
  * just before commit/rollback of transactions, like {@link TransactionSystemException}. Such
@@ -73,11 +74,12 @@ public class ServerExceptionTranslatingAdvisor extends DefaultPointcutAdvisor
             try
             {
                 return invocation.proceed();
-            } catch (NestedRuntimeException e) // e.g. TransactionSystemException
+            } catch (NestedRuntimeException ex)
+            // e.g. TransactionSystemException, DataAccessException
             {
                 // Deferred trigger may throw an exception just before commit.
                 // Message in the exception is readable for the user.
-                throw new UserFailureException(e.getMostSpecificCause().getMessage());
+                throw new UserFailureException(ex.getMostSpecificCause().getMessage(), ex);
             }
         }
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ITrashBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ITrashBO.java
index 70bc1384c5a..547e1f275cf 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ITrashBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/ITrashBO.java
@@ -28,6 +28,8 @@ import ch.systemsx.cisd.openbis.generic.shared.dto.DataPE;
  */
 public interface ITrashBO
 {
+    /** Puts back all objects moved to trash in deletion with specified id. */
+    public void revertDeletion(TechId deletionId);
 
     public void createDeletion(String reason);
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/TrashBO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/TrashBO.java
index c18f65406d6..a4429a7d27d 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/TrashBO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/TrashBO.java
@@ -36,13 +36,24 @@ public class TrashBO extends AbstractBusinessObject implements ITrashBO
 
     private DeletionPE deletion;
 
-    public TrashBO(IDAOFactory daoFactory, Session session,
-            ICommonBusinessObjectFactory boFactory)
+    public TrashBO(IDAOFactory daoFactory, Session session, ICommonBusinessObjectFactory boFactory)
     {
         super(daoFactory, session);
         this.boFactory = boFactory;
     }
 
+    public void revertDeletion(TechId deletionId)
+    {
+        try
+        {
+            deletion = getDeletionDAO().getByTechId(deletionId);
+            getDeletionDAO().delete(deletion);
+        } catch (final DataAccessException ex)
+        {
+            throwException(ex, "Deletion");
+        }
+    }
+
     public void createDeletion(String reason)
     {
         try
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
index ff6713ec3fd..e31399cbf6e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/dataaccess/db/DeletionDAO.java
@@ -27,6 +27,7 @@ import ch.systemsx.cisd.common.logging.LogFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDeletionDAO;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DatabaseInstancePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
+import ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind;
 
 /**
  * <i>Data Access Object</i> implementation for {@link IDeletionDAO}.
@@ -66,4 +67,33 @@ final class DeletionDAO extends AbstractGenericEntityDAO<DeletionPE> implements
         }
     }
 
+    @Override
+    public void delete(DeletionPE deletion) throws DataAccessException
+    {
+        operationLog.info(String.format("REVERT: deletion %s.", deletion));
+        for (EntityKind entityKind : EntityKind.values())
+        {
+            // NOTE: material deletion are always permanent and therefore can't be reverted
+            if (entityKind != EntityKind.MATERIAL)
+            {
+                revertDeletion(deletion, entityKind);
+            }
+        }
+        super.delete(deletion);
+    }
+
+    private void revertDeletion(final DeletionPE deletion,
+            final ch.systemsx.cisd.openbis.generic.shared.dto.properties.EntityKind entityKind)
+    {
+        assert deletion != null : "Unspecified deletion";
+        assert entityKind != null : "Unspecified entity kind";
+
+        final HibernateTemplate hibernateTemplate = getHibernateTemplate();
+        String query =
+                String.format("UPDATE VERSIONED %s SET deletion = NULL WHERE deletion = ?",
+                        entityKind.getEntityClass().getSimpleName());
+        int updatedRows = hibernateTemplate.bulkUpdate(query, deletion);
+        hibernateTemplate.flush();
+        operationLog.info(String.format("%s %s(s) reverted", updatedRows, entityKind.name()));
+    }
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
index 8d2ed5673eb..5bf5c02c3a1 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java
@@ -1399,6 +1399,7 @@ public interface ICommonServer extends IServer
      */
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     public void updateDataSetProperties(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId entityId,
             List<PropertyUpdates> modifiedProperties);
@@ -1408,6 +1409,7 @@ public interface ICommonServer extends IServer
      */
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @DatabaseUpdateModification(value = ObjectKind.EXPERIMENT)
     public void updateExperimentProperties(String sessionToken,
             @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId entityId,
             List<PropertyUpdates> modifiedProperties);
@@ -1417,6 +1419,7 @@ public interface ICommonServer extends IServer
      */
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
     public void updateSampleProperties(String sessionToken,
             @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId entityId,
             List<PropertyUpdates> modifiedProperties);
@@ -1426,6 +1429,7 @@ public interface ICommonServer extends IServer
      */
     @Transactional
     @RolesAllowed(RoleWithHierarchy.INSTANCE_ADMIN)
+    @DatabaseUpdateModification(value = ObjectKind.MATERIAL)
     public void updateMaterialProperties(String sessionToken, TechId entityId,
             List<PropertyUpdates> modifiedProperties);
 
@@ -1439,4 +1443,15 @@ public interface ICommonServer extends IServer
     @ReturnValueFilter(validatorClass = DeletionValidator.class)
     public List<Deletion> listDeletions(String sessionToken);
 
+    /**
+     * Reverts specified deletion (puts back all objects moved to trash in the deletion).
+     */
+    @Transactional
+    // TODO make it possible for deletion creator
+    @RolesAllowed(RoleWithHierarchy.INSTANCE_ADMIN)
+    @DatabaseCreateOrDeleteModification(value = ObjectKind.DELETION)
+    @DatabaseUpdateModification(value =
+        { ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
+    public void revertDeletions(final String sessionToken, final List<TechId> deletionIds);
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/Deletion.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/Deletion.java
index 955d5558877..e47b3b7a242 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/Deletion.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/basic/dto/Deletion.java
@@ -16,15 +16,19 @@
 
 package ch.systemsx.cisd.openbis.generic.shared.basic.dto;
 
+import ch.systemsx.cisd.openbis.generic.shared.basic.IIdHolder;
+
 /**
  * Information about deletion.
  * 
  * @author Christian Ribeaud
  */
-public final class Deletion extends AbstractRegistrationHolder
+public final class Deletion extends AbstractRegistrationHolder implements IIdHolder
 {
     private static final long serialVersionUID = ServiceVersionHolder.VERSION;
 
+    private Long id;
+
     /** Reason of deletion. */
     private String reasonOrNull;
 
@@ -37,4 +41,15 @@ public final class Deletion extends AbstractRegistrationHolder
     {
         this.reasonOrNull = reasonOrNull;
     }
+
+    public Long getId()
+    {
+        return id;
+    }
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/DeletionTranslator.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/DeletionTranslator.java
index 09e8eb1d8a3..6973d5d311f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/DeletionTranslator.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/translator/DeletionTranslator.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
+import ch.systemsx.cisd.openbis.generic.shared.util.HibernateUtils;
 
 /**
  * A <i>static</i> class for translating {@link DeletionPE} into {@link Deletion}.
@@ -52,6 +53,9 @@ public final class DeletionTranslator
             return null;
         }
         final Deletion newDeletion = new Deletion();
+        // NOTE: we should always translate Id in this way
+        // because getId() on HibernateProxy object always returns null
+        newDeletion.setId(HibernateUtils.getId(deletion));
         newDeletion.setReason(deletion.getReason());
         newDeletion.setRegistrationDate(deletion.getRegistrationDate());
         newDeletion.setRegistrator(PersonTranslator.translate(deletion.getRegistrator()));
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js b/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
index fb41934b7a8..21ff93ef957 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/public/common-dictionary.js
@@ -77,6 +77,8 @@ var common = {
   deletion_browser: "Trash",
   button_revert_deletion: "Revert",
   button_delete_permanently: "Delete Permanently",
+  revert_deletions_confirmation_title: "Confirm Revert",
+  revert_deletions_confirmation_msg: "Are you sure you want to revert {0} deletion(s)?",
 	 
   //
   // Table Modifications
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java.expected b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java.expected
index 8d2ed5673eb..5bf5c02c3a1 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java.expected
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/shared/ICommonServer.java.expected
@@ -1399,6 +1399,7 @@ public interface ICommonServer extends IServer
      */
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @DatabaseUpdateModification(value = ObjectKind.DATA_SET)
     public void updateDataSetProperties(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetTechIdPredicate.class) TechId entityId,
             List<PropertyUpdates> modifiedProperties);
@@ -1408,6 +1409,7 @@ public interface ICommonServer extends IServer
      */
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @DatabaseUpdateModification(value = ObjectKind.EXPERIMENT)
     public void updateExperimentProperties(String sessionToken,
             @AuthorizationGuard(guardClass = ExperimentTechIdPredicate.class) TechId entityId,
             List<PropertyUpdates> modifiedProperties);
@@ -1417,6 +1419,7 @@ public interface ICommonServer extends IServer
      */
     @Transactional
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @DatabaseUpdateModification(value = ObjectKind.SAMPLE)
     public void updateSampleProperties(String sessionToken,
             @AuthorizationGuard(guardClass = SampleTechIdPredicate.class) TechId entityId,
             List<PropertyUpdates> modifiedProperties);
@@ -1426,6 +1429,7 @@ public interface ICommonServer extends IServer
      */
     @Transactional
     @RolesAllowed(RoleWithHierarchy.INSTANCE_ADMIN)
+    @DatabaseUpdateModification(value = ObjectKind.MATERIAL)
     public void updateMaterialProperties(String sessionToken, TechId entityId,
             List<PropertyUpdates> modifiedProperties);
 
@@ -1439,4 +1443,15 @@ public interface ICommonServer extends IServer
     @ReturnValueFilter(validatorClass = DeletionValidator.class)
     public List<Deletion> listDeletions(String sessionToken);
 
+    /**
+     * Reverts specified deletion (puts back all objects moved to trash in the deletion).
+     */
+    @Transactional
+    // TODO make it possible for deletion creator
+    @RolesAllowed(RoleWithHierarchy.INSTANCE_ADMIN)
+    @DatabaseCreateOrDeleteModification(value = ObjectKind.DELETION)
+    @DatabaseUpdateModification(value =
+        { ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
+    public void revertDeletions(final String sessionToken, final List<TechId> deletionIds);
+
 }
-- 
GitLab