From d0a90e2b078c33a73ef2fa4b61c38dab98a99aa6 Mon Sep 17 00:00:00 2001
From: jakubs <jakubs>
Date: Tue, 5 Mar 2013 09:57:46 +0000
Subject: [PATCH] SP-483 BIS-319 Opening the trash is slow

SVN: 28518
---
 .../server/resultset/DeletionsProvider.java   |  78 ++++++++----
 .../openbis/generic/server/CommonServer.java  |  11 ++
 .../generic/server/CommonServerLogger.java    |   7 +
 .../server/business/bo/DeletionTable.java     | 120 +++++++++++++-----
 .../server/business/bo/IDeletionTable.java    |  11 +-
 .../openbis/generic/shared/ICommonServer.java |   8 ++
 .../generic/shared/basic/dto/Deletion.java    |  40 ++++++
 7 files changed, 215 insertions(+), 60 deletions(-)

diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/DeletionsProvider.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/DeletionsProvider.java
index 0a54a9bc4c4..0baf298cd69 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/DeletionsProvider.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/client/web/server/resultset/DeletionsProvider.java
@@ -47,7 +47,7 @@ public class DeletionsProvider extends AbstractCommonTableModelProvider<Deletion
     @Override
     protected TypedTableModel<Deletion> createTableModel()
     {
-        List<Deletion> deletions = commonServer.listDeletions(sessionToken, true);
+        List<Deletion> deletions = commonServer.listDeletions(sessionToken, MAX_NUMBER);
         TypedTableModelBuilder<Deletion> builder = new TypedTableModelBuilder<Deletion>();
         builder.addColumn(DELETION_DATE).withDefaultWidth(300);
         builder.addColumn(DELETER).withDefaultWidth(200);
@@ -59,48 +59,40 @@ public class DeletionsProvider extends AbstractCommonTableModelProvider<Deletion
             builder.column(DELETION_DATE).addDate(deletion.getRegistrationDate());
             builder.column(DELETER).addPerson(deletion.getRegistrator());
             builder.column(REASON).addString(deletion.getReason());
-            List<IEntityInformationHolderWithIdentifier> deletedEntities =
-                    deletion.getDeletedEntities();
-            if (deletedEntities.isEmpty() == false)
+            if (deletion.getDeletedEntities().isEmpty() == false)
             {
-                builder.column(ENTITIES).addString(
-                        createDescriptionOfDeletedEntities(deletedEntities));
+                builder.column(ENTITIES).addString(createDescriptionOfDeletedEntities(deletion));
             }
         }
         return builder.getModel();
     }
 
-    private String createDescriptionOfDeletedEntities(
-            List<IEntityInformationHolderWithIdentifier> deletedEntities)
+    private String createDescriptionOfDeletedEntities(Deletion deletion)
     {
         StringBuilder builder = new StringBuilder();
-        String experiments = createList(deletedEntities, EntityKind.EXPERIMENT);
+        String experiments = createList(deletion, EntityKind.EXPERIMENT, "Experiment");
         if (experiments.length() > 0)
         {
-            builder.append(moreThenOneLine(experiments) ? "Experiments:\n" : "Experiment ");
             builder.append(experiments);
         }
-        String samples = createList(deletedEntities, EntityKind.SAMPLE);
+        String samples = createList(deletion, EntityKind.SAMPLE, "Sample");
         if (samples.length() > 0)
         {
-            builder.append(moreThenOneLine(samples) ? "Samples:\n" : "Sample ");
             builder.append(samples);
         }
-        String dataSets = createList(deletedEntities, EntityKind.DATA_SET);
+        String dataSets = createList(deletion, EntityKind.DATA_SET, "Data Set");
         if (dataSets.length() > 0)
         {
-            builder.append(moreThenOneLine(dataSets) ? "Data Sets:\n" : "Data Set ");
             builder.append(dataSets);
         }
         return builder.toString();
     }
 
-    private String createList(List<IEntityInformationHolderWithIdentifier> deletedEntities,
-            EntityKind entityKind)
+    private String createList(Deletion deletion, EntityKind entityKind, String name)
     {
         StringBuilder builder = new StringBuilder();
         int count = 0;
-        for (IEntityInformationHolderWithIdentifier entity : deletedEntities)
+        for (IEntityInformationHolderWithIdentifier entity : deletion.getDeletedEntities())
         {
             if (entity.getEntityKind() == entityKind)
             {
@@ -108,20 +100,56 @@ public class DeletionsProvider extends AbstractCommonTableModelProvider<Deletion
                 {
                     builder.append("  ").append(entity.getIdentifier()).append(" (");
                     builder.append(entity.getEntityType().getCode()).append(")\n");
+                    count++;
                 }
-                count++;
             }
         }
-        int numberOfAdditionalEntities = count - MAX_NUMBER;
+
+        int numberOfAdditionalEntities = 0;
+
+        switch (entityKind)
+        {
+            case DATA_SET:
+                numberOfAdditionalEntities = deletion.getTotalDatasetsCount();
+                break;
+            case SAMPLE:
+                numberOfAdditionalEntities = deletion.getTotalSamplesCount();
+                break;
+            case EXPERIMENT:
+                numberOfAdditionalEntities = deletion.getTotalExperimentsCount();
+                break;
+            default:
+                // nothing
+                break;
+        }
+
+        numberOfAdditionalEntities -= count;
+
+        if (count == 0)
+        {
+            if (numberOfAdditionalEntities == 0)
+            {
+                return "";
+            } else if (numberOfAdditionalEntities == 1)
+            {
+                return "1 " + name + "\n";
+            } else if (numberOfAdditionalEntities > 1)
+            {
+                return numberOfAdditionalEntities + " " + name + "s\n";
+            }
+        }
+
         if (numberOfAdditionalEntities > 0)
         {
-            builder.append("  and ").append(numberOfAdditionalEntities).append(" more");
+            builder.append("  and ").append(numberOfAdditionalEntities).append(" more\n");
         }
-        return builder.toString();
-    }
 
-    private boolean moreThenOneLine(String text)
-    {
-        return text.split("\n").length > 1;
+        if (count == 1)
+        {
+            return name + " " + builder.toString();
+        }
+
+        return name + "s:\n" + builder.toString();
     }
+
 }
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 4b222b457e2..0864ac939c7 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
@@ -3693,6 +3693,17 @@ public final class CommonServer extends AbstractCommonServer<ICommonServerForInt
         return deletionTable.getDeletions();
     }
 
+    @Override
+    @RolesAllowed(RoleWithHierarchy.SPACE_USER)
+    @ReturnValueFilter(validatorClass = DeletionValidator.class)
+    public List<Deletion> listDeletions(String sessionToken, int limit)
+    {
+        Session session = getSession(sessionToken);
+        IDeletionTable deletionTable = businessObjectFactory.createDeletionTable(session);
+        deletionTable.load(limit);
+        return deletionTable.getDeletions();
+    }
+
     @Override
     @RolesAllowed(RoleWithHierarchy.SPACE_USER)
     @Capability("RESTORE")
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 ca409c71091..5349cd480a9 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
@@ -1453,6 +1453,13 @@ final class CommonServerLogger extends AbstractServerLogger implements ICommonSe
         return null;
     }
 
+    @Override
+    public List<Deletion> listDeletions(String sessionToken, int limit)
+    {
+        logAccess(sessionToken, "listDeletions", "LIMIT(%s)", limit);
+        return null;
+    }
+
     @Override
     public void revertDeletions(String sessionToken, List<TechId> deletionIds)
     {
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DeletionTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DeletionTable.java
index 7ac99d3004d..d2854cefbfe 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DeletionTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/DeletionTable.java
@@ -25,9 +25,6 @@ import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDAOFactory;
 import ch.systemsx.cisd.openbis.generic.server.dataaccess.IDeletionDAO;
 import ch.systemsx.cisd.openbis.generic.shared.basic.TechId;
 import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DeletedDataPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DeletedExperimentPE;
-import ch.systemsx.cisd.openbis.generic.shared.dto.DeletedSamplePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.DeletionPE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.IDeletablePE;
 import ch.systemsx.cisd.openbis.generic.shared.dto.Session;
@@ -58,6 +55,17 @@ public class DeletionTable extends AbstractBusinessObject implements IDeletionTa
 
     @Override
     public void load(boolean withEntities)
+    {
+        load(withEntities, 0);
+    }
+
+    @Override
+    public void load(int limit)
+    {
+        load(true, limit);
+    }
+
+    private void load(boolean withEntities, int limit)
     {
         final List<DeletionPE> deletionPEs = getDeletionDAO().listAllEntities();
         Collections.sort(deletionPEs);
@@ -71,12 +79,12 @@ public class DeletionTable extends AbstractBusinessObject implements IDeletionTa
         {
             findersMap.put(deletionPE.getId(), new RootEntitiesFinder());
         }
-        List<TechId> deletionIDs = TechId.createList(deletionPEs);
-        if (false == deletionIDs.isEmpty())
+
+        if (false == deletions.isEmpty())
         {
-            findExperiments(findersMap, deletionIDs);
-            findSamples(findersMap, deletionIDs);
-            findDataSets(findersMap, deletionIDs);
+            findEntities(TrashEntity.EXPERIMENT, findersMap, limit);
+            findEntities(TrashEntity.SAMPLE, findersMap, limit);
+            findEntities(TrashEntity.DATA_SET, findersMap, limit);
         }
         for (Deletion deletion : deletions)
         {
@@ -84,38 +92,84 @@ public class DeletionTable extends AbstractBusinessObject implements IDeletionTa
         }
     }
 
-    private void findDataSets(Map<Long, RootEntitiesFinder> findersMap, List<TechId> deletionIDs)
+    private void findEntities(TrashEntity kind, Map<Long, RootEntitiesFinder> findersMap, int limit)
     {
         IDeletionDAO deletionDAO = getDeletionDAO();
-        List<TechId> deletedDataSetIds = deletionDAO.findTrashedDataSetIds(deletionIDs);
-        List<DeletedDataPE> dataSets =
-                cast(getDeletionDAO().listDeletedEntities(EntityKind.DATA_SET, deletedDataSetIds));
-        addEntities(dataSets, findersMap);
-    }
 
-    private void findSamples(Map<Long, RootEntitiesFinder> findersMap, List<TechId> deletionIDs)
-    {
-        IDeletionDAO deletionDAO = getDeletionDAO();
-        List<TechId> deletedSampleIds = deletionDAO.findTrashedSampleIds(deletionIDs);
-        List<DeletedSamplePE> samples =
-                cast(getDeletionDAO().listDeletedEntities(EntityKind.SAMPLE, deletedSampleIds));
-        addEntities(samples, findersMap);
-    }
+        for (Deletion deletion : deletions)
+        {
+            List<TechId> deletedEntitiesIds =
+                    kind.deletedEntityIds(deletionDAO,
+                            Collections.singletonList(new TechId(deletion.getId())));
+            EntityKind entityKind = kind.entityKind;
+            int count = deletedEntitiesIds.size();
+
+            switch (entityKind)
+            {
+                case DATA_SET:
+                    deletion.setTotalDatasetsCount(count);
+                    break;
+                case SAMPLE:
+                    deletion.setTotalSamplesCount(count);
+                    break;
+                case EXPERIMENT:
+                    deletion.setTotalExperimentsCount(count);
+                    break;
+                default:
+                    throw new IllegalArgumentException("Unsupported entity type " + entityKind);
+            }
+            if (limit > 0 && limit < deletedEntitiesIds.size())
+            {
+                deletedEntitiesIds = deletedEntitiesIds.subList(0, limit);
+            }
+
+            List<? extends IDeletablePE> entities =
+                    deletionDAO.listDeletedEntities(kind.entityKind, deletedEntitiesIds);
+            addEntities(entities, findersMap);
+
+        }
 
-    private void findExperiments(Map<Long, RootEntitiesFinder> findersMap, List<TechId> deletionIDs)
-    {
-        IDeletionDAO deletionDAO = getDeletionDAO();
-        List<TechId> deletedExperimentIds = deletionDAO.findTrashedExperimentIds(deletionIDs);
-        List<DeletedExperimentPE> experiments =
-                cast(getDeletionDAO().listDeletedEntities(EntityKind.EXPERIMENT,
-                        deletedExperimentIds));
-        addEntities(experiments, findersMap);
     }
 
-    @SuppressWarnings("unchecked")
-    private final static <T> T cast(final Object object)
+    private enum TrashEntity
     {
-        return (T) object;
+        SAMPLE(EntityKind.SAMPLE)
+        {
+            @Override
+            List<TechId> deletedEntityIds(IDeletionDAO dao, List<TechId> deletionIDs)
+            {
+                return dao.findTrashedSampleIds(deletionIDs);
+            }
+
+        },
+        EXPERIMENT(EntityKind.EXPERIMENT)
+        {
+            @Override
+            List<TechId> deletedEntityIds(IDeletionDAO dao, List<TechId> deletionIDs)
+            {
+                return dao.findTrashedExperimentIds(deletionIDs);
+            }
+
+        },
+        DATA_SET(EntityKind.DATA_SET)
+        {
+            @Override
+            List<TechId> deletedEntityIds(IDeletionDAO dao, List<TechId> deletionIDs)
+            {
+                return dao.findTrashedDataSetIds(deletionIDs);
+            }
+
+        };
+
+        private TrashEntity(EntityKind entityKind)
+        {
+            this.entityKind = entityKind;
+        }
+
+        final EntityKind entityKind;
+
+        abstract List<TechId> deletedEntityIds(IDeletionDAO dao, List<TechId> deletionIDs);
+
     }
 
     private void addEntities(List<? extends IDeletablePE> entities,
diff --git a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDeletionTable.java b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDeletionTable.java
index 2af98a7863e..4392bf08abf 100644
--- a/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDeletionTable.java
+++ b/openbis/source/java/ch/systemsx/cisd/openbis/generic/server/business/bo/IDeletionTable.java
@@ -22,7 +22,7 @@ import ch.systemsx.cisd.openbis.generic.shared.basic.dto.Deletion;
 
 /**
  * Business object handling table of {@link Deletion} objects.
- *
+ * 
  * @author Franz-Josef Elmer
  */
 public interface IDeletionTable
@@ -34,6 +34,13 @@ public interface IDeletionTable
      *            entities which are the root of the deletion tree.
      */
     public void load(boolean withEntities);
-    
+
+    /**
+     * Load all {@link Deletion} objects.
+     * 
+     * @param limit will fetch only that many entities of certain type
+     */
+    public void load(int limit);
+
     public List<Deletion> getDeletions();
 }
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 c041ea9a1db..fdb5456f2a8 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
@@ -1358,6 +1358,14 @@ public interface ICommonServer extends IServer
     @Transactional(readOnly = true)
     public List<Deletion> listDeletions(String sessionToken, boolean withDeletedEntities);
 
+    /**
+     * Returns all deletions. Additionally limit number of entities fetched per limit per item
+     * 
+     * @return a sorted list of {@link Deletion}.
+     */
+    @Transactional(readOnly = true)
+    public List<Deletion> listDeletions(String sessionToken, int limit);
+
     /**
      * Reverts specified deletions (puts back all entities moved to trash in the deletions).
      */
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 599b972fd1d..04be5dce282 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
@@ -33,6 +33,12 @@ public final class Deletion extends AbstractRegistrationHolder implements IIdHol
 
     private Long id;
 
+    private int totalSamplesCount;
+
+    private int totalDatasetsCount;
+
+    private int totalExperimentsCount;
+
     /** Reason of deletion. */
     private String reasonOrNull;
 
@@ -70,4 +76,38 @@ public final class Deletion extends AbstractRegistrationHolder implements IIdHol
         return deletedEntities;
     }
 
+    /*
+     * The deletion counts are supposed to be used in situations when not all deleted entities are
+     * fetched into the <code>deletedEntities<?code>
+     */
+    public int getTotalSamplesCount()
+    {
+        return totalSamplesCount;
+    }
+
+    public void setTotalSamplesCount(int totalSamplesCount)
+    {
+        this.totalSamplesCount = totalSamplesCount;
+    }
+
+    public int getTotalDatasetsCount()
+    {
+        return totalDatasetsCount;
+    }
+
+    public void setTotalDatasetsCount(int totalDatasetsCount)
+    {
+        this.totalDatasetsCount = totalDatasetsCount;
+    }
+
+    public int getTotalExperimentsCount()
+    {
+        return totalExperimentsCount;
+    }
+
+    public void setTotalExperimentsCount(int totalExperimentsCount)
+    {
+        this.totalExperimentsCount = totalExperimentsCount;
+    }
+
 }
-- 
GitLab