From 3bc986abdf906883df9a5787b39589676b65d16b Mon Sep 17 00:00:00 2001
From: gpawel <gpawel>
Date: Mon, 22 Aug 2011 11:45:17 +0000
Subject: [PATCH] [LMS-2379] - Allow to delete a dataset even if it's not on
 the file system

SVN: 22576
---
 .../dss/generic/server/DataStoreService.java  |  11 +-
 .../server/DataStoreServiceLogger.java        |   9 ++
 .../web/client/ICommonClientService.java      |   8 +-
 .../web/client/ICommonClientServiceAsync.java |  12 +-
 .../client/web/client/application/Dict.java   |   8 ++
 ...DataSetListDeletionConfirmationDialog.java |  22 +++-
 .../application/ui/deletion/DeletionGrid.java |   6 +-
 .../ui/deletion/EmptyTrashButtonMenu.java     | 118 ++++++++++++++++++
 .../EmptyTrashConfirmationDialog.java         |   6 +-
 ...actDataListDeletionConfirmationDialog.java |   3 +-
 .../web/server/CommonClientService.java       |  15 +--
 .../openbis/generic/server/CommonServer.java  |  16 +--
 .../generic/server/CommonServerLogger.java    |  13 +-
 .../server/business/bo/DataSetTable.java      |  17 +--
 .../business/bo/DeletedDataSetTable.java      |  16 ++-
 .../server/business/bo/IDataSetTable.java     |   2 +-
 .../business/bo/IDeletedDataSetTable.java     |   2 +-
 .../plugin/IDataSetTypeSlaveServerPlugin.java |   8 +-
 .../openbis/generic/shared/ICommonServer.java |   5 +-
 .../generic/shared/IDataStoreService.java     |  15 ++-
 .../GenericDataSetTypeSlaveServerPlugin.java  |   5 +-
 .../cisd/openbis/public/common-dictionary.js  |   4 +
 .../generic/server/CommonServerTest.java      |  12 +-
 .../server/business/bo/DataSetTableTest.java  |  14 +--
 .../shared/ICommonServer.java.expected        |   5 +-
 .../openbis/systemtest/DeletionTestCase.java  |  18 +--
 26 files changed, 287 insertions(+), 83 deletions(-)
 create mode 100644 openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/EmptyTrashButtonMenu.java

diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
index 94537b37ffd..63eda059741 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreService.java
@@ -232,6 +232,13 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic
 
     public List<String> getKnownDataSets(String sessionToken,
             List<? extends IDatasetLocation> dataSets) throws InvalidAuthenticationException
+    {
+        return getKnownDataSets(sessionToken, dataSets, false);
+    }
+
+    public List<String> getKnownDataSets(String sessionToken,
+            List<? extends IDatasetLocation> dataSets, boolean ignoreNonExistingLocation)
+            throws InvalidAuthenticationException
     {
         sessionTokenManager.assertValidSessionToken(sessionToken);
 
@@ -245,8 +252,8 @@ public class DataStoreService extends AbstractServiceWithLogger<IDataStoreServic
             try
             {
                 if (manager.isKnown(datasetCode)
-                        && new File(new File(storeRoot, manager.getShareId(datasetCode)), location)
-                                .exists())
+                        && (ignoreNonExistingLocation || new File(new File(storeRoot,
+                                manager.getShareId(datasetCode)), location).exists()))
                 {
                     knownLocations.add(location);
                 }
diff --git a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
index ac249a99ca7..52b65ac64ad 100644
--- a/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
+++ b/datastore_server/source/java/ch/systemsx/cisd/openbis/dss/generic/server/DataStoreServiceLogger.java
@@ -93,6 +93,15 @@ class DataStoreServiceLogger implements IDataStoreService, IInitializable
         return null;
     }
 
+    public List<String> getKnownDataSets(String sessionToken,
+            List<? extends IDatasetLocation> dataSetLocations, boolean ignoreNonExistingLocation)
+            throws InvalidAuthenticationException
+    {
+        log("getKnownDataSets", "DATA_SETS(%s) IGNORE_NON_EXISTING_LOCATION(%s)", dataSetLocations,
+                ignoreNonExistingLocation);
+        return null;
+    }
+
     public void deleteDataSets(String sessionToken, List<? extends IDatasetLocation> dataSets)
             throws InvalidAuthenticationException
     {
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 8d45e8aab4e..fa824ef8248 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
@@ -649,11 +649,11 @@ public interface ICommonClientService extends IClientService
     /** Deletes/Trashes the specified data sets. */
     public void deleteDataSets(
             DisplayedOrSelectedDatasetCriteria displayedOrSelectedDatasetCriteria, String reason,
-            DeletionType deletionType) throws UserFailureException;
+            DeletionType deletionType, boolean force) throws UserFailureException;
 
     /** Deletes/Trashes the specified data set. */
-    public void deleteDataSet(String singleData, String reason, DeletionType deletionType)
-            throws UserFailureException;
+    public void deleteDataSet(String singleData, String reason, DeletionType deletionType,
+            boolean force) throws UserFailureException;
 
     /**
      * Deletes/Trashes the specified samples. NOTE: this is a stale version used only for samples
@@ -1102,6 +1102,6 @@ public interface ICommonClientService extends IClientService
     /**
      * Permanently deletes all entities moved to trash.
      */
-    public void emptyTrash() throws UserFailureException;
+    public void emptyTrash(boolean force) 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 cc0adef110f..4144f7096f3 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
@@ -546,15 +546,15 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
 
     /**
      * @see ICommonClientService#deleteDataSets(DisplayedOrSelectedDatasetCriteria, String,
-     *      DeletionType)
+     *      DeletionType, boolean)
      */
     public void deleteDataSets(
             DisplayedOrSelectedDatasetCriteria displayedOrSelectedDatasetCriteria, String reason,
-            DeletionType deletionType, AsyncCallback<Void> asyncCallback);
+            DeletionType deletionType, boolean force, AsyncCallback<Void> asyncCallback);
 
-    /** @see ICommonClientService#deleteDataSet(String, String, DeletionType) */
+    /** @see ICommonClientService#deleteDataSet(String, String, DeletionType, boolean) */
     public void deleteDataSet(String singleData, String reason, DeletionType deletionType,
-            AsyncCallback<Void> asyncCallback);
+            boolean force, AsyncCallback<Void> asyncCallback);
 
     /** @see ICommonClientService#deleteSamples(List, String, DeletionType) */
     public void deleteSamples(List<TechId> sampleIds, String reason, DeletionType deletionType,
@@ -995,7 +995,7 @@ public interface ICommonClientServiceAsync extends IClientServiceAsync
     public void deletePermanently(List<TechId> deletionIds, AsyncCallback<Void> callback);
 
     /**
-     * @see ICommonClientService#emptyTrash()
+     * @see ICommonClientService#emptyTrash(boolean)
      */
-    public void emptyTrash(AsyncCallback<Void> callback);
+    public void emptyTrash(boolean force, 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 b196d656be3..c3d984b21dc 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
@@ -503,6 +503,8 @@ public abstract class Dict
 
     public static final String DELETING_PERMANENTLY = "deleting_permanently";
 
+    public static final String DELETING_FORCE = "deleting_force";
+
     public static final String DELETING = "deleting";
 
     public static final String DELETE_PERMANENTLY_PROGRESS_MESSAGE =
@@ -522,6 +524,12 @@ public abstract class Dict
 
     public static final String BUTTON_EMPTY_TRASH = "button_empty_trash";
 
+    public static final String BUTTON_FORCE_EMPTY_TRASH = "button_force_empty_trash";
+
+    public static final String TOOLTIP_EMPTY_TRASH = "tooltip_empty_trash";
+
+    public static final String TOOLTIP_FORCE_EMPTY_TRASH = "tooltip_force_empty_trash";
+
     public static final String BUTTON_DELETE_PERMANENTLY = "button_delete_permanently";
 
     public static final String REVERT_DELETIONS_CONFIRMATION_TITLE =
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetListDeletionConfirmationDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetListDeletionConfirmationDialog.java
index 801293d1869..cbb5cfb5720 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetListDeletionConfirmationDialog.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/data/DataSetListDeletionConfirmationDialog.java
@@ -18,6 +18,7 @@ package ch.systemsx.cisd.openbis.generic.client.web.client.application.ui.data;
 
 import java.util.Collections;
 
+import com.extjs.gxt.ui.client.widget.form.CheckBox;
 import com.extjs.gxt.ui.client.widget.form.RadioGroup;
 import com.google.gwt.user.client.rpc.AsyncCallback;
 
@@ -40,6 +41,8 @@ public final class DataSetListDeletionConfirmationDialog extends
 
     private final ExternalData singleData;
 
+    protected CheckBox force;
+
     public DataSetListDeletionConfirmationDialog(
             IViewContext<ICommonClientServiceAsync> viewContext, AsyncCallback<Void> callback,
             SelectedAndDisplayedItems selectedAndDisplayedItems)
@@ -74,11 +77,12 @@ public final class DataSetListDeletionConfirmationDialog extends
             final DisplayedOrSelectedDatasetCriteria uploadCriteria =
                     selectedAndDisplayedItemsOrNull.createCriteria(isOnlySelected());
             getViewContext().getCommonService().deleteDataSets(uploadCriteria, reason.getValue(),
-                    deletionType, deletionCallback);
+                    deletionType, isTrashEnabled() ? false : force.getValue(), deletionCallback);
         } else
         {
             getViewContext().getCommonService().deleteDataSet(singleData.getCode(),
-                    reason.getValue(), deletionType, deletionCallback);
+                    reason.getValue(), deletionType, isTrashEnabled() ? false : force.getValue(),
+                    deletionCallback);
         }
     }
 
@@ -99,4 +103,18 @@ public final class DataSetListDeletionConfirmationDialog extends
                         Dict.ALL_RADIO, selectedAndDisplayedItemsOrNull.getDisplayedItemsCount())),
                 context.getMessage(Dict.DATA_SETS_RADIO_GROUP_LABEL), data.size());
     }
+
+    @Override
+    protected void extendForm()
+    {
+        super.extendForm();
+
+        if (false == isTrashEnabled())
+        {
+            force = new CheckBox();
+            force.setBoxLabel("");
+            force.setFieldLabel(messageProvider.getMessage(Dict.DELETING_FORCE));
+            formPanel.add(force);
+        }
+    }
 }
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 4732eace24f..be6988e01e1 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
@@ -102,12 +102,16 @@ public class DeletionGrid extends TypedTableGrid<Deletion>
                                 @Override
                                 public void componentSelected(ButtonEvent ce)
                                 {
-                                    new EmptyTrashConfirmationDialog(viewContext,
+                                    new EmptyTrashConfirmationDialog(viewContext, false,
                                             createRefreshCallback(asActionInvoker())).show();
                                 }
                             });
         addButton(emptyTrashButton);
 
+        EmptyTrashButtonMenu emptyTrashButtonMenu =
+                new EmptyTrashButtonMenu(viewContext, createRefreshCallback(asActionInvoker()));
+        addButton(emptyTrashButtonMenu);
+
         Button deletePermanentlyButton =
                 createSelectedItemsButton(viewContext.getMessage(Dict.BUTTON_DELETE_PERMANENTLY),
                         new AbstractCreateDialogListener()
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/EmptyTrashButtonMenu.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/EmptyTrashButtonMenu.java
new file mode 100644
index 00000000000..d4a52ebe795
--- /dev/null
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/EmptyTrashButtonMenu.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2011 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 com.extjs.gxt.ui.client.event.ButtonEvent;
+import com.extjs.gxt.ui.client.event.MenuEvent;
+import com.extjs.gxt.ui.client.event.SelectionListener;
+import com.extjs.gxt.ui.client.widget.button.SplitButton;
+import com.extjs.gxt.ui.client.widget.menu.CheckMenuItem;
+import com.extjs.gxt.ui.client.widget.menu.Menu;
+
+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.util.GWTUtils;
+
+/**
+ * @author Pawel Glyzewski
+ */
+public class EmptyTrashButtonMenu extends SplitButton
+{
+    private final IViewContext<ICommonClientServiceAsync> viewContext;
+
+    private final CheckMenuItem emptyTrash;
+
+    private final CheckMenuItem forceEmptyTrash;
+
+    public EmptyTrashButtonMenu(final IViewContext<ICommonClientServiceAsync> viewContext,
+            final AbstractAsyncCallback<Void> callback)
+    {
+        super(viewContext.getMessage(Dict.BUTTON_EMPTY_TRASH));
+        this.viewContext = viewContext;
+
+        final Menu exportMenu = new Menu();
+        emptyTrash = new CheckMenuItem(viewContext.getMessage(Dict.BUTTON_EMPTY_TRASH));
+        forceEmptyTrash = new CheckMenuItem(viewContext.getMessage(Dict.BUTTON_FORCE_EMPTY_TRASH));
+
+        emptyTrash.setToolTip(viewContext.getMessage(Dict.TOOLTIP_EMPTY_TRASH));
+        forceEmptyTrash.setToolTip(viewContext.getMessage(Dict.TOOLTIP_FORCE_EMPTY_TRASH));
+
+        emptyTrash.setGroup("deletionType");
+        forceEmptyTrash.setGroup("deletionType");
+
+        exportMenu.add(emptyTrash);
+        exportMenu.add(forceEmptyTrash);
+
+        setMenu(exportMenu);
+
+        addSelectionListener(new SelectionListener<ButtonEvent>()
+            {
+                @Override
+                public void componentSelected(ButtonEvent be)
+                {
+                    invokeAction(callback);
+                }
+            });
+
+        SelectionListener<MenuEvent> menuEventListener = new SelectionListener<MenuEvent>()
+            {
+                @Override
+                public void componentSelected(MenuEvent ce)
+                {
+                    boolean isExportAllColumns = isForceEmptyTrash();
+                    invokeAction(callback);
+                    setText(isExportAllColumns ? viewContext
+                            .getMessage(Dict.BUTTON_FORCE_EMPTY_TRASH) : viewContext
+                            .getMessage(Dict.BUTTON_EMPTY_TRASH));
+                    updateTooltip();
+                }
+
+            };
+        emptyTrash.addSelectionListener(menuEventListener);
+        forceEmptyTrash.addSelectionListener(menuEventListener);
+
+        // select export visible columns by default
+        emptyTrash.setChecked(true);
+    }
+
+    private void invokeAction(final AbstractAsyncCallback<Void> callback)
+    {
+        new EmptyTrashConfirmationDialog(viewContext, isForceEmptyTrash(), callback).show();
+    }
+
+    private boolean isForceEmptyTrash()
+    {
+        return forceEmptyTrash.isChecked();
+    }
+
+    private void updateTooltip()
+    {
+        String enabledButtonMessageKey =
+                isForceEmptyTrash() ? Dict.TOOLTIP_FORCE_EMPTY_TRASH : Dict.TOOLTIP_EMPTY_TRASH;
+        String title = viewContext.getMessage(enabledButtonMessageKey);
+        GWTUtils.setToolTip(this, title);
+    }
+
+    @Override
+    public void enable()
+    {
+        super.enable();
+        updateTooltip();
+    }
+}
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/EmptyTrashConfirmationDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/EmptyTrashConfirmationDialog.java
index 3a0b01522ec..d4509cadaa9 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/EmptyTrashConfirmationDialog.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/deletion/EmptyTrashConfirmationDialog.java
@@ -39,12 +39,15 @@ public final class EmptyTrashConfirmationDialog extends
 
     private final AsyncCallback<Void> callback;
 
+    private final boolean force;
+
     public EmptyTrashConfirmationDialog(IViewContext<ICommonClientServiceAsync> viewContext,
-            AsyncCallback<Void> callback)
+            boolean force, AsyncCallback<Void> callback)
     {
         super(viewContext, Collections.<Deletion> emptyList(), viewContext
                 .getMessage(Dict.EMPTY_TRASH_CONFIRMATION_TITLE));
         this.viewContext = viewContext;
+        this.force = force;
         this.callback = callback;
     }
 
@@ -52,6 +55,7 @@ public final class EmptyTrashConfirmationDialog extends
     protected void executeConfirmedAction()
     {
         viewContext.getCommonService().emptyTrash(
+                force,
                 AsyncCallbackWithProgressBar.decorate(callback,
                         viewContext.getMessage(Dict.EMPTY_TRASH_PROGRESS)));
     }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/widget/AbstractDataListDeletionConfirmationDialog.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/widget/AbstractDataListDeletionConfirmationDialog.java
index 694bf6e6030..d7fbc40c86e 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/widget/AbstractDataListDeletionConfirmationDialog.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/client/application/ui/widget/AbstractDataListDeletionConfirmationDialog.java
@@ -87,6 +87,7 @@ public abstract class AbstractDataListDeletionConfirmationDialog<T> extends
         {
             formPanel.add(createRadio());
         }
+
         formPanel.add(reason);
     }
 
@@ -131,7 +132,7 @@ public abstract class AbstractDataListDeletionConfirmationDialog<T> extends
         return viewContext.getMessage(dictKey, getEntityName());
     }
 
-    private final boolean isTrashEnabled()
+    protected final boolean isTrashEnabled()
     {
         return viewContext.getModel().getApplicationInfo().getWebClientConfiguration()
                 .getEnableTrash();
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 5785b4a716b..178ef13e42c 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
@@ -1300,23 +1300,24 @@ public final class CommonClientService extends AbstractClientService implements
         return commonServer.uploadDataSets(sessionToken, dataSetCodes, uploadContext);
     }
 
-    public void deleteDataSet(String singleData, String reason, DeletionType deletionType)
+    public void deleteDataSet(String singleData, String reason, DeletionType deletionType,
+            boolean force)
             throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
     {
         final String sessionToken = getSessionToken();
         List<String> dataSetCodes = Collections.singletonList(singleData);
-        commonServer.deleteDataSets(sessionToken, dataSetCodes, reason, deletionType,
+        commonServer.deleteDataSets(sessionToken, dataSetCodes, reason, deletionType, force,
                 isTrashEnabled());
     }
 
     public void deleteDataSets(
             DisplayedOrSelectedDatasetCriteria displayedOrSelectedDatasetCriteria, String reason,
-            DeletionType deletionType)
+            DeletionType deletionType, boolean force)
             throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
     {
         final String sessionToken = getSessionToken();
         List<String> dataSetCodes = extractDatasetCodes(displayedOrSelectedDatasetCriteria);
-        commonServer.deleteDataSets(sessionToken, dataSetCodes, reason, deletionType,
+        commonServer.deleteDataSets(sessionToken, dataSetCodes, reason, deletionType, force,
                 isTrashEnabled());
     }
 
@@ -2233,15 +2234,15 @@ public final class CommonClientService extends AbstractClientService implements
     public void deletePermanently(List<TechId> deletionIds)
             throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
     {
-        commonServer.deletePermanently(getSessionToken(), deletionIds);
+        commonServer.deletePermanently(getSessionToken(), deletionIds, false);
     }
 
-    public void emptyTrash()
+    public void emptyTrash(boolean force)
             throws ch.systemsx.cisd.openbis.generic.client.web.client.exception.UserFailureException
     {
         String sessionToken = getSessionToken();
         List<Deletion> deletions = commonServer.listDeletions(sessionToken);
-        commonServer.deletePermanently(sessionToken, TechId.createList(deletions));
+        commonServer.deletePermanently(sessionToken, TechId.createList(deletions), force);
     }
 
 }
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 9b23a4c0179..908ef117e75 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
@@ -1096,7 +1096,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
     }
 
     public void deleteDataSets(String sessionToken, List<String> dataSetCodes, String reason,
-            DeletionType deletionType, boolean isTrashEnabled)
+            DeletionType deletionType, boolean force, boolean isTrashEnabled)
     {
         // TODO 2011-08-09, Piotr Buczek: simplify it when we remove the switch turning off trash
         // provide data set ids directly (no need to use codes)
@@ -1111,10 +1111,10 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
                     IDeletedDataSetTable deletedDataSetTable =
                             businessObjectFactory.createDeletedDataSetTable(session);
                     deletedDataSetTable.loadByDataSetCodes(dataSetCodes);
-                    deletedDataSetTable.permanentlyDeleteLoadedDataSets(reason);
+                    deletedDataSetTable.permanentlyDeleteLoadedDataSets(reason, force);
                 } else
                 {
-                    permanentlyDeleteDataSets(session, dataSetCodes, reason);
+                    permanentlyDeleteDataSets(session, dataSetCodes, reason, force);
                 }
                 break;
             case TRASH:
@@ -1130,7 +1130,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
 
     @Deprecated
     /** @deprecated this is legacy code permanently deleting data sets one by one omitting trash */
-    private void permanentlyDeleteDataSets(Session session, List<String> dataSetCodes, String reason)
+    private void permanentlyDeleteDataSets(Session session, List<String> dataSetCodes,
+            String reason, boolean force)
     {
         IDataSetTable dataSetTable = businessObjectFactory.createDataSetTable(session);
         // TODO 2011-06-21, Piotr Buczek: loading less for deletion would probably be faster
@@ -1153,7 +1154,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         {
             DataSetTypePE dataSetType = entry.getKey();
             IDataSetTypeSlaveServerPlugin plugin = getDataSetTypeSlaveServerPlugin(dataSetType);
-            plugin.permanentlyDeleteDataSets(session, entry.getValue(), reason);
+            plugin.permanentlyDeleteDataSets(session, entry.getValue(), reason, force);
         }
     }
 
@@ -2430,7 +2431,8 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         }
     }
 
-    public final void deletePermanently(final String sessionToken, final List<TechId> deletionIds)
+    public final void deletePermanently(final String sessionToken, final List<TechId> deletionIds,
+            boolean force)
     {
         checkSession(sessionToken);
 
@@ -2444,7 +2446,7 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
 
             List<TechId> singletonList = Collections.singletonList(deletionId);
             List<String> trashedDataSets = deletionDAO.findTrashedDataSetCodes(singletonList);
-            deleteDataSets(sessionToken, trashedDataSets, deletionReason, deletionType, true);
+            deleteDataSets(sessionToken, trashedDataSets, deletionReason, deletionType, force, true);
 
             // we need to first delete components and then containers not to break constraints
             List<TechId> trashedComponentSamples =
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 5850c85daf8..26689b22cb4 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
@@ -575,10 +575,10 @@ final class CommonServerLogger extends AbstractServerLogger implements ICommonSe
     }
 
     public void deleteDataSets(String sessionToken, List<String> dataSetCodes, String reason,
-            DeletionType deletionType, boolean isTrashEnabled)
+            DeletionType deletionType, boolean force, boolean isTrashEnabled)
     {
-        logTracking(sessionToken, "delete_data_sets", "TYPE(%s) CODES(%s) REASON(%s)",
-                deletionType, abbreviate(dataSetCodes), reason);
+        logTracking(sessionToken, "delete_data_sets", "TYPE(%s) CODES(%s) REASON(%s) FORCE(%s)",
+                deletionType, abbreviate(dataSetCodes), reason, force);
     }
 
     public void deleteSamples(String sessionToken, List<TechId> sampleIds, String reason,
@@ -1114,7 +1114,7 @@ final class CommonServerLogger extends AbstractServerLogger implements ICommonSe
             List<PropertyUpdates> modifiedProperties)
 
     {
-        logTracking(sessionToken, "updateMaterialProperty", "ID(%s) MODIFIED_PROPERTIES(%s)",
+        logTracking(sessionToken, "updateMaterialProperty", "ID(%s), MODIFIED_PROPERTIES(%s)",
                 entityId, abbreviate(modifiedProperties));
     }
 
@@ -1137,9 +1137,10 @@ final class CommonServerLogger extends AbstractServerLogger implements ICommonSe
         logTracking(sessionToken, "revertDeletions", "ID(%s)", abbreviate(deletionIds));
     }
 
-    public void deletePermanently(String sessionToken, List<TechId> deletionIds)
+    public void deletePermanently(String sessionToken, List<TechId> deletionIds, boolean force)
     {
-        logTracking(sessionToken, "deletePermanently", "ID(%s)", abbreviate(deletionIds));
+        logTracking(sessionToken, "deletePermanently", "ID(%s), FORCE(%s)",
+                abbreviate(deletionIds), force);
     }
 
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java
index f70a9590011..e48caae2b90 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTable.java
@@ -234,7 +234,7 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements
         dataSets.addAll(getDataDAO().listDataSets(experiment));
     }
 
-    public void deleteLoadedDataSets(String reason)
+    public void deleteLoadedDataSets(String reason, boolean force)
     {
         assertDatasetsAreDeletable(dataSets);
 
@@ -242,7 +242,7 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements
         Map<DataStorePE, List<ExternalDataPE>> availableDatasets =
                 filterAvailableDatasets(allToBeDeleted);
 
-        assertDataSetsAreKnown(availableDatasets);
+        assertDataSetsAreKnown(availableDatasets, force);
         for (Map.Entry<DataStorePE, List<DataPE>> entry : allToBeDeleted.entrySet())
         {
             DataStorePE dataStore = entry.getKey();
@@ -327,7 +327,7 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements
     {
         assertDatasetsAreAvailable(dataSets);
         Map<DataStorePE, List<DataPE>> map = groupDataByDataStores();
-        assertDataSetsAreKnown(map);
+        assertDataSetsAreKnown(map, false);
         uploadContext.setUserEMail(session.getPrincipal().getEmail());
         uploadContext.setSessionUserID(session.getUserName());
         if (StringUtils.isBlank(uploadContext.getComment()))
@@ -375,7 +375,8 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements
         return builder.toString();
     }
 
-    private <D extends DataPE> void assertDataSetsAreKnown(Map<DataStorePE, List<D>> map)
+    private <D extends DataPE> void assertDataSetsAreKnown(Map<DataStorePE, List<D>> map,
+            boolean ignoreNonExistingLocation)
     {
         // Set<String> knownLocations = new LinkedHashSet<String>();
         List<String> unknownDataSets = new ArrayList<String>();
@@ -384,7 +385,8 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements
             DataStorePE dataStore = entry.getKey();
             List<ExternalDataPE> externalDatas = filterRealDataSets(entry.getValue());
             Set<String> knownLocations =
-                    getKnownDataSets(dataStore, createDatasetDescriptions(externalDatas));
+                    getKnownDataSets(dataStore, createDatasetDescriptions(externalDatas),
+                            ignoreNonExistingLocation);
             for (ExternalDataPE dataSet : externalDatas)
             {
                 if (dataSet.getStatus() == DataSetArchivingStatus.ARCHIVED)
@@ -510,7 +512,7 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements
     }
 
     private Set<String> getKnownDataSets(DataStorePE dataStore,
-            List<DatasetDescription> dataSetDescriptions)
+            List<DatasetDescription> dataSetDescriptions, boolean ignoreNonExistingLocation)
     {
         String remoteURL = dataStore.getRemoteUrl();
         if (StringUtils.isBlank(remoteURL))
@@ -525,7 +527,8 @@ public final class DataSetTable extends AbstractDataSetBusinessObject implements
         }
         IDataStoreService service = dssFactory.create(remoteURL);
         String sessionToken = dataStore.getSessionToken();
-        return new HashSet<String>(service.getKnownDataSets(sessionToken, dataSetDescriptions));
+        return new HashSet<String>(service.getKnownDataSets(sessionToken, dataSetDescriptions,
+                ignoreNonExistingLocation));
     }
 
     public void processDatasets(String datastoreServiceKey, String datastoreCode,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DeletedDataSetTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DeletedDataSetTable.java
index 0338b3606e6..4f1a7de02b3 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DeletedDataSetTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DeletedDataSetTable.java
@@ -94,7 +94,7 @@ public final class DeletedDataSetTable extends AbstractDataSetBusinessObject imp
         deletedDataSets.addAll(dataDAO.tryToFindDeletedDataSetsByCodes(dataSetCodes));
     }
 
-    public void permanentlyDeleteLoadedDataSets(String reason)
+    public void permanentlyDeleteLoadedDataSets(String reason, boolean force)
     {
         assertDatasetsAreDeletable(deletedDataSets);
 
@@ -102,7 +102,7 @@ public final class DeletedDataSetTable extends AbstractDataSetBusinessObject imp
         Map<DataStorePE, List<DeletedExternalDataPE>> availableDatasets =
                 filterAvailableDatasets(allToBeDeleted);
 
-        assertDataSetsAreKnown(availableDatasets);
+        assertDataSetsAreKnown(availableDatasets, force);
         for (Map.Entry<DataStorePE, List<DeletedDataPE>> entry : allToBeDeleted.entrySet())
         {
             DataStorePE dataStore = entry.getKey();
@@ -159,7 +159,8 @@ public final class DeletedDataSetTable extends AbstractDataSetBusinessObject imp
         return result;
     }
 
-    private void assertDataSetsAreKnown(Map<DataStorePE, List<DeletedExternalDataPE>> map)
+    private void assertDataSetsAreKnown(Map<DataStorePE, List<DeletedExternalDataPE>> map,
+            boolean ignoreNonExistingLocation)
     {
         List<String> unknownDataSets = new ArrayList<String>();
         for (Map.Entry<DataStorePE, List<DeletedExternalDataPE>> entry : map.entrySet())
@@ -167,7 +168,8 @@ public final class DeletedDataSetTable extends AbstractDataSetBusinessObject imp
             DataStorePE dataStore = entry.getKey();
             List<DeletedExternalDataPE> externalDataSets = entry.getValue();
             Set<String> knownLocations =
-                    getKnownDataSets(dataStore, extractDatasetLocations(externalDataSets));
+                    getKnownDataSets(dataStore, extractDatasetLocations(externalDataSets),
+                            ignoreNonExistingLocation);
             for (DeletedExternalDataPE dataSet : externalDataSets)
             {
                 if (knownLocations.contains(dataSet.getLocation()) == false)
@@ -231,7 +233,8 @@ public final class DeletedDataSetTable extends AbstractDataSetBusinessObject imp
         return dssFactory.create(remoteURL);
     }
 
-    private Set<String> getKnownDataSets(DataStorePE dataStore, List<IDatasetLocation> dataSets)
+    private Set<String> getKnownDataSets(DataStorePE dataStore, List<IDatasetLocation> dataSets,
+            boolean ignoreNonExistingLocation)
     {
         String remoteURL = dataStore.getRemoteUrl();
         if (StringUtils.isBlank(remoteURL))
@@ -246,7 +249,8 @@ public final class DeletedDataSetTable extends AbstractDataSetBusinessObject imp
         }
         IDataStoreService service = dssFactory.create(remoteURL);
         String sessionToken = dataStore.getSessionToken();
-        return new HashSet<String>(service.getKnownDataSets(sessionToken, dataSets));
+        return new HashSet<String>(service.getKnownDataSets(sessionToken, dataSets,
+                ignoreNonExistingLocation));
     }
 
     private List<IDatasetLocation> extractDatasetLocations(List<DeletedExternalDataPE> datasets)
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataSetTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataSetTable.java
index 895671ce203..961e37d3691 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataSetTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDataSetTable.java
@@ -71,7 +71,7 @@ public interface IDataSetTable
     /**
      * Permanently Deletes loaded data sets for specified reason.
      */
-    void deleteLoadedDataSets(String reason);
+    void deleteLoadedDataSets(String reason, boolean force);
 
     /**
      * Uploads loaded data sets to CIFEX server as specified in the upload context.
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDeletedDataSetTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDeletedDataSetTable.java
index e6548548d10..f155a3e6600 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDeletedDataSetTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDeletedDataSetTable.java
@@ -30,7 +30,7 @@ public interface IDeletedDataSetTable
     /**
      * Permanently Deletes loaded data sets for specified reason.
      */
-    void permanentlyDeleteLoadedDataSets(String reason);
+    void permanentlyDeleteLoadedDataSets(String reason, boolean force);
 
     void loadByDataSetCodes(List<String> dataSetCodes);
 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/plugin/IDataSetTypeSlaveServerPlugin.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/plugin/IDataSetTypeSlaveServerPlugin.java
index b6adef83583..2d5f8b256c6 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/plugin/IDataSetTypeSlaveServerPlugin.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/plugin/IDataSetTypeSlaveServerPlugin.java
@@ -37,11 +37,13 @@ public interface IDataSetTypeSlaveServerPlugin
 {
     /**
      * Permanently deletes the specified data sets for the specified reason.
-     *
-     * @deprecated this is legacy code and should be removed when we remove the option of disabled trash
+     * 
+     * @deprecated this is legacy code and should be removed when we remove the option of disabled
+     *             trash
      */
     @Deprecated
-    public void permanentlyDeleteDataSets(Session session, List<DataPE> dataSets, String reason);
+    public void permanentlyDeleteDataSets(Session session, List<DataPE> dataSets, String reason,
+            boolean force);
 
     /**
      * Updates properties of given data sets.
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 eb14b924c30..26c6f714985 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
@@ -761,7 +761,7 @@ public interface ICommonServer extends IServer
         { ObjectKind.DATA_SET, ObjectKind.DELETION })
     public void deleteDataSets(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes,
-            String reason, DeletionType type, boolean isTrashEnabled);
+            String reason, DeletionType type, boolean force, boolean isTrashEnabled);
 
     /**
      * Deletes/Trashes specified samples.
@@ -1466,5 +1466,6 @@ public interface ICommonServer extends IServer
         { ObjectKind.DELETION, ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     public void deletePermanently(
             final String sessionToken,
-            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds);
+            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds,
+            boolean force);
 }
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
index 3709e62fb95..ca4de7bfa9f 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/shared/IDataStoreService.java
@@ -50,7 +50,8 @@ public interface IDataStoreService
     public int getVersion(String sessionToken) throws InvalidAuthenticationException;
 
     /**
-     * Returns from the specified data sets those known by the Data Store Server.
+     * Returns from the specified data sets those known by the Data Store Server. Data set not
+     * available on the filesystem is classified as not known.
      * 
      * @param sessionToken Valid token to identify authorised access.
      * @return locations (as strings) of known data sets
@@ -59,6 +60,18 @@ public interface IDataStoreService
     public List<String> getKnownDataSets(String sessionToken,
             List<? extends IDatasetLocation> dataSets) throws InvalidAuthenticationException;
 
+    /**
+     * Returns from the specified data sets those known by the Data Store Server.
+     * 
+     * @param sessionToken Valid token to identify authorised access.
+     * @param ignoreNonExistingLocation specifies if non-existing locations should be ignored.
+     * @return locations (as strings) of known data sets
+     * @throws InvalidAuthenticationException if <code>sessionToken</code> is invalid.
+     */
+    public List<String> getKnownDataSets(String sessionToken,
+            List<? extends IDatasetLocation> dataSets, boolean ignoreNonExistingLocation)
+            throws InvalidAuthenticationException;
+
     /**
      * Deletes the specified data sets.
      * 
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java
index 110513c16f6..a17fbb4454b 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/plugin/generic/server/GenericDataSetTypeSlaveServerPlugin.java
@@ -46,11 +46,12 @@ public class GenericDataSetTypeSlaveServerPlugin implements IDataSetTypeSlaveSer
     {
     }
 
-    public void permanentlyDeleteDataSets(Session session, List<DataPE> dataSets, String reason)
+    public void permanentlyDeleteDataSets(Session session, List<DataPE> dataSets, String reason,
+            boolean force)
     {
         IDataSetTable dataSetTable = businessObjectFactory.createDataSetTable(session);
         dataSetTable.setDataSets(dataSets);
-        dataSetTable.deleteLoadedDataSets(reason);
+        dataSetTable.deleteLoadedDataSets(reason, force);
     }
 
     public void updateDataSets(Session session, List<NewDataSet> newDataSets)
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 9b441b8d6ba..3c9f8f283d2 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
@@ -71,6 +71,7 @@ var common = {
   delete_confirmation_message: "Are you sure you want to delete [{0}]?",
   delete_confirmation_message_with_reason_template: "You are {0} {1}(s).<br><br>Please enter a reason or cancel the operation.",
   deleting_permanently: "<b>permanently</b> deleting",
+  deleting_force: "Force?",
   deleting: "Deleting",
   delete_permanently_progress_message: "Deleting {0}(s)...",
   delete_progress_message: "Moving {0}(s) to trash ...",
@@ -79,6 +80,9 @@ var common = {
   deletion_browser: "Trash",
   button_revert_deletion: "Revert",
   button_empty_trash: "Empty Trash",
+  button_force_empty_trash: "Force Empty Trash",
+  tooltip_empty_trash: "Deletes permanently all the entities in trashcan.",
+  tooltip_force_empty_trash: "Forces permanent deletion of all the entities in trashcan.",
   button_delete_permanently: "Delete Permanently",
   revert_deletions_confirmation_title: "Confirm Revert",
   revert_deletions_progress: "Reverting deletion(s)...",
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
index 7463337c9e0..75d80f8f84f 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/CommonServerTest.java
@@ -1391,14 +1391,14 @@ public final class CommonServerTest extends AbstractServerTestCase
                     will(returnValue(Arrays.asList(ds1, ds2, ds3)));
 
                     one(dataSetTypeSlaveServerPlugin).permanentlyDeleteDataSets(SESSION,
-                            Arrays.asList(ds1, ds2), reason);
+                            Arrays.asList(ds1, ds2), reason, false);
                     one(dataSetTypeSlaveServerPlugin).permanentlyDeleteDataSets(SESSION,
-                            Arrays.asList(ds3), reason);
+                            Arrays.asList(ds3), reason, false);
                 }
             });
 
         createServer().deleteDataSets(SESSION_TOKEN, dataSetCodes, reason, DeletionType.PERMANENT,
-                enableTrash);
+                false, enableTrash);
 
         context.assertIsSatisfied();
     }
@@ -1417,12 +1417,12 @@ public final class CommonServerTest extends AbstractServerTestCase
                     will(returnValue(deletedDataSetTable));
 
                     one(deletedDataSetTable).loadByDataSetCodes(dataSetCodes);
-                    one(deletedDataSetTable).permanentlyDeleteLoadedDataSets(reason);
+                    one(deletedDataSetTable).permanentlyDeleteLoadedDataSets(reason, false);
                 }
             });
 
         createServer().deleteDataSets(SESSION_TOKEN, dataSetCodes, reason, DeletionType.PERMANENT,
-                enableTrash);
+                false, enableTrash);
 
         context.assertIsSatisfied();
     }
@@ -1459,7 +1459,7 @@ public final class CommonServerTest extends AbstractServerTestCase
             });
 
         createServer().deleteDataSets(SESSION_TOKEN, dataSetCodes, reason, DeletionType.TRASH,
-                enableTrash);
+                false, enableTrash);
 
         context.assertIsSatisfied();
     }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTableTest.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTableTest.java
index d1026a78d78..95e3cf472aa 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTableTest.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DataSetTableTest.java
@@ -244,7 +244,7 @@ public final class DataSetTableTest extends AbstractBOTest
                         { d1, d2 }, false, false);
 
                     one(dataStoreService2).getKnownDataSets(with(dss2.getSessionToken()),
-                            with(createDatasetDescriptionsMatcher(d2)));
+                            with(createDatasetDescriptionsMatcher(d2)), with(false));
                     will(returnValue(Arrays.asList()));
                 }
             });
@@ -253,7 +253,7 @@ public final class DataSetTableTest extends AbstractBOTest
         dataSetTable.loadByDataSetCodes(Arrays.asList(d1.getCode(), d2.getCode()), false, false);
         try
         {
-            dataSetTable.deleteLoadedDataSets("");
+            dataSetTable.deleteLoadedDataSets("", false);
             fail("UserFailureException expected");
         } catch (UserFailureException e)
         {
@@ -286,14 +286,14 @@ public final class DataSetTableTest extends AbstractBOTest
                 .loadByDataSetCodes(Code.extractCodes(Arrays.asList(allDataSets)), false, false);
         try
         {
-            dataSetTable.deleteLoadedDataSets("");
+            dataSetTable.deleteLoadedDataSets("", false);
             fail("UserFailureException expected");
         } catch (UserFailureException e)
         {
             Pattern pattern =
                     Pattern.compile("Deletion failed because the following data sets are "
                             + "required by a background process \\(their status is pending\\): "
-                            +"\\[(.*)\\]. ");
+                            + "\\[(.*)\\]. ");
             Matcher matcher = pattern.matcher(e.getMessage());
 
             assertTrue("Invalid error message:" + e.getMessage(), matcher.matches());
@@ -320,7 +320,7 @@ public final class DataSetTableTest extends AbstractBOTest
                     BaseMatcher<List<DatasetDescription>> dataSets =
                             createDatasetDescriptionsMatcher(d2);
                     one(dataStoreService2).getKnownDataSets(with(dss2.getSessionToken()),
-                            with(dataSets));
+                            with(dataSets), with(false));
                     will(returnValue(Arrays.asList(d2.getLocation())));
 
                     PersonPE person = EXAMPLE_SESSION.tryGetPerson();
@@ -336,7 +336,7 @@ public final class DataSetTableTest extends AbstractBOTest
 
         DataSetTable dataSetTable = createDataSetTable();
         dataSetTable.loadByDataSetCodes(Arrays.asList(d1.getCode(), d2.getCode()), false, false);
-        dataSetTable.deleteLoadedDataSets(reason);
+        dataSetTable.deleteLoadedDataSets(reason, false);
     }
 
     private EventPE createDeletionEvent(ExternalDataPE dataset, PersonPE person, String reason)
@@ -363,7 +363,7 @@ public final class DataSetTableTest extends AbstractBOTest
                         { d1PE, d2PE }, true, false);
 
                     one(dataStoreService2).getKnownDataSets(with(dss2.getSessionToken()),
-                            with(createDatasetDescriptionsMatcher(d2PE)));
+                            with(createDatasetDescriptionsMatcher(d2PE)), with(false));
                     will(returnValue(Arrays.asList(d2PE.getLocation())));
 
                     one(dataStoreService2).uploadDataSetsToCIFEX(
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 eb14b924c30..26c6f714985 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
@@ -761,7 +761,7 @@ public interface ICommonServer extends IServer
         { ObjectKind.DATA_SET, ObjectKind.DELETION })
     public void deleteDataSets(String sessionToken,
             @AuthorizationGuard(guardClass = DataSetCodePredicate.class) List<String> dataSetCodes,
-            String reason, DeletionType type, boolean isTrashEnabled);
+            String reason, DeletionType type, boolean force, boolean isTrashEnabled);
 
     /**
      * Deletes/Trashes specified samples.
@@ -1466,5 +1466,6 @@ public interface ICommonServer extends IServer
         { ObjectKind.DELETION, ObjectKind.EXPERIMENT, ObjectKind.SAMPLE, ObjectKind.DATA_SET })
     public void deletePermanently(
             final String sessionToken,
-            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds);
+            @AuthorizationGuard(guardClass = DeletionTechIdCollectionPredicate.class) final List<TechId> deletionIds,
+            boolean force);
 }
diff --git a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/DeletionTestCase.java b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/DeletionTestCase.java
index ddf0fd7379c..4d7e964fd72 100644
--- a/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/DeletionTestCase.java
+++ b/openbis/sourceTest/java/ch/systemsx/cisd/openbis/systemtest/DeletionTestCase.java
@@ -81,7 +81,8 @@ public class DeletionTestCase extends SystemTestCase
     }
 
     @BeforeMethod
-    public void setUp() {
+    public void setUp()
+    {
         registeredExperiments = new ArrayList<Experiment>();
         registeredSamples = new ArrayList<Sample>();
 
@@ -150,7 +151,7 @@ public class DeletionTestCase extends SystemTestCase
         }
         commonServer.deleteExperiments(sessionToken, TechId.createList(existingExperiments),
                 REASON, DeletionType.TRASH);
-        commonServer.deletePermanently(sessionToken, TechId.createList(listDeletions()));
+        commonServer.deletePermanently(sessionToken, TechId.createList(listDeletions()), false);
     }
 
     @Test
@@ -162,13 +163,13 @@ public class DeletionTestCase extends SystemTestCase
         // delete
         commonServer.deleteExperiments(sessionToken, Collections.singletonList(experimentId),
                 REASON, DeletionType.TRASH);
-        
+
         assertExperimentDoesNotExist(e1.getCode());
         assertSamplesDoNotExist(registeredSamples);
-        
+
         List<DeletionPE> deletions = listDeletions();
         Assert.assertEquals(1, deletions.size());
-        
+
         // revert
         final TechId deletionId1 = TechId.create(deletions.get(0));
         commonServer.revertDeletions(sessionToken, Collections.singletonList(deletionId1));
@@ -180,7 +181,7 @@ public class DeletionTestCase extends SystemTestCase
         commonServer.deleteExperiments(sessionToken, Collections.singletonList(experimentId),
                 REASON, DeletionType.TRASH);
         final TechId deletionId2 = TechId.create(listDeletions().get(0));
-        commonServer.deletePermanently(sessionToken, Collections.singletonList(deletionId2));
+        commonServer.deletePermanently(sessionToken, Collections.singletonList(deletionId2), false);
         assertExperimentDoesNotExist(e1.getCode());
         assertSamplesDoNotExist(registeredSamples);
     }
@@ -212,7 +213,7 @@ public class DeletionTestCase extends SystemTestCase
         commonServer.deleteSamples(sessionToken, Collections.singletonList(sampleId), REASON,
                 DeletionType.TRASH);
         final TechId deletionId2 = TechId.create(listDeletions().get(0));
-        commonServer.deletePermanently(sessionToken, Collections.singletonList(deletionId2));
+        commonServer.deletePermanently(sessionToken, Collections.singletonList(deletionId2), false);
         assertExperimentExists("E1");
         assertSamplesDoNotExist(deletedSamples);
     }
@@ -288,7 +289,8 @@ public class DeletionTestCase extends SystemTestCase
                 new ExperimentIdentifier(null, "CISD", "DEFAULT", code);
         NewExperiment experiment = new NewExperiment(expIdentifier.toString(), "COMPOUND_HCS");
         final GenericEntityProperty property = createDescriptionProperty();
-        experiment.setProperties(new IEntityProperty[] { property });
+        experiment.setProperties(new IEntityProperty[]
+            { property });
         long id = etlService.registerExperiment(sessionToken, experiment);
 
         Experiment exp = commonServer.getExperimentInfo(sessionToken, new TechId(id));
-- 
GitLab