syncope-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From skylar...@apache.org
Subject syncope git commit: [SYNCOPE-1288] Task lists are now correctly sortable
Date Thu, 05 Apr 2018 13:59:55 GMT
Repository: syncope
Updated Branches:
  refs/heads/2_0_X 79354db35 -> bb508d9fa


[SYNCOPE-1288] Task lists are now correctly sortable


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/bb508d9f
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/bb508d9f
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/bb508d9f

Branch: refs/heads/2_0_X
Commit: bb508d9faf3ba5ea85fc5a377e517dcd8b9476c6
Parents: 79354db
Author: skylark17 <matteo.alessandroni@tirasa.net>
Authored: Thu Apr 5 15:59:48 2018 +0200
Committer: skylark17 <matteo.alessandroni@tirasa.net>
Committed: Thu Apr 5 15:59:48 2018 +0200

----------------------------------------------------------------------
 .../console/reports/ReportDirectoryPanel.java   |   4 +-
 .../tasks/ProvisioningTaskDirectoryPanel.java   |   4 +-
 .../console/tasks/SchedTaskDirectoryPanel.java  |   4 +-
 .../core/persistence/jpa/dao/JPATaskDAO.java    | 243 ++++++++++++++++---
 .../core/persistence/jpa/outer/TaskTest.java    | 127 +++++-----
 .../syncope/fit/core/PropagationTaskITCase.java |  78 ++++++
 6 files changed, 361 insertions(+), 99 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
index e0c5d6f..ceef254 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
@@ -110,10 +110,10 @@ public abstract class ReportDirectoryPanel
                 "name", this), "name", "name"));
 
         columns.add(new DatePropertyColumn<ReportTO>(
-                new StringResourceModel("lastExec", this), "lastExec", "lastExec"));
+                new StringResourceModel("lastExec", this), null, "lastExec"));
 
         columns.add(new DatePropertyColumn<ReportTO>(
-                new StringResourceModel("nextExec", this), "nextExec", "nextExec"));
+                new StringResourceModel("nextExec", this), null, "nextExec"));
 
         columns.add(new DatePropertyColumn<ReportTO>(
                 new StringResourceModel("start", this), "start", "start"));

http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
b/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
index cacd6f7..59802b4 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/ProvisioningTaskDirectoryPanel.java
@@ -117,10 +117,10 @@ public abstract class ProvisioningTaskDirectoryPanel<T extends ProvisioningTaskT
         }
 
         columns.add(new DatePropertyColumn<T>(
-                new StringResourceModel("lastExec", this), "lastExec", "lastExec"));
+                new StringResourceModel("lastExec", this), null, "lastExec"));
 
         columns.add(new DatePropertyColumn<T>(
-                new StringResourceModel("nextExec", this), "nextExec", "nextExec"));
+                new StringResourceModel("nextExec", this), null, "nextExec"));
 
         columns.add(new PropertyColumn<T, String>(
                 new StringResourceModel("latestExecStatus", this), "latestExecStatus", "latestExecStatus"));

http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
index a4b2d51..a57856a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
@@ -164,10 +164,10 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO>
         });
 
         columns.add(new DatePropertyColumn<T>(
-                new StringResourceModel("lastExec", this), "lastExec", "lastExec"));
+                new StringResourceModel("lastExec", this), null, "lastExec"));
 
         columns.add(new DatePropertyColumn<T>(
-                new StringResourceModel("nextExec", this), "nextExec", "nextExec"));
+                new StringResourceModel("nextExec", this), null, "nextExec"));
 
         columns.add(new PropertyColumn<T, String>(
                 new StringResourceModel("latestExecStatus", this), "latestExecStatus", "latestExecStatus"));

http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
index dfb7536..f6ee96c 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
@@ -18,11 +18,17 @@
  */
 package org.apache.syncope.core.persistence.jpa.dao;
 
+import java.lang.reflect.Field;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import javax.persistence.DiscriminatorValue;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
 import javax.persistence.Query;
 import org.apache.commons.collections4.Closure;
 import org.apache.commons.collections4.IterableUtils;
+import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.TaskType;
@@ -37,6 +43,7 @@ import org.apache.syncope.core.persistence.jpa.entity.task.JPAPushTask;
 import org.apache.syncope.core.persistence.jpa.entity.task.JPASchedTask;
 import org.apache.syncope.core.persistence.jpa.entity.task.JPAPullTask;
 import org.apache.syncope.core.persistence.jpa.entity.task.AbstractTask;
+import org.apache.syncope.core.persistence.jpa.entity.task.JPATaskExec;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ReflectionUtils;
@@ -75,6 +82,36 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO
{
         return result;
     }
 
+    private String getEntityTableName(final TaskType type) {
+        String result = null;
+
+        switch (type) {
+            case NOTIFICATION:
+                result = JPANotificationTask.class.getAnnotation(DiscriminatorValue.class).value();
+                break;
+
+            case PROPAGATION:
+                result = JPAPropagationTask.class.getAnnotation(DiscriminatorValue.class).value();
+                break;
+
+            case PUSH:
+                result = JPAPushTask.class.getAnnotation(DiscriminatorValue.class).value();
+                break;
+
+            case SCHEDULED:
+                result = JPASchedTask.class.getAnnotation(DiscriminatorValue.class).value();
+                break;
+
+            case PULL:
+                result = JPAPullTask.class.getAnnotation(DiscriminatorValue.class).value();
+                break;
+
+            default:
+        }
+
+        return result;
+    }
+
     @Transactional(readOnly = true)
     @SuppressWarnings("unchecked")
     @Override
@@ -82,7 +119,7 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO
{
         return (T) entityManager().find(AbstractTask.class, key);
     }
 
-    private <T extends Task> StringBuilder buildFindAllQuery(final TaskType type) {
+    private <T extends Task> StringBuilder buildFindAllQueryJPA(final TaskType type)
{
         StringBuilder builder = new StringBuilder("SELECT t FROM ").
                 append(getEntityReference(type).getSimpleName()).
                 append(" t WHERE ");
@@ -102,7 +139,7 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO
{
     @Override
     @SuppressWarnings("unchecked")
     public <T extends Task> List<T> findToExec(final TaskType type) {
-        StringBuilder queryString = buildFindAllQuery(type).append("AND ");
+        StringBuilder queryString = buildFindAllQueryJPA(type).append("AND ");
 
         if (type == TaskType.NOTIFICATION) {
             queryString.append("t.executed = 0 ");
@@ -126,7 +163,9 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO
{
             final ExternalResource resource,
             final Notification notification,
             final AnyTypeKind anyTypeKind,
-            final String entityKey) {
+            final String entityKey,
+            final boolean orderByTaskExecInfo,
+            final List<Object> queryParameters) {
 
         if (resource != null
                 && type != TaskType.PROPAGATION && type != TaskType.PUSH
&& type != TaskType.PULL) {
@@ -144,38 +183,135 @@ public class JPATaskDAO extends AbstractDAO<Task> implements
TaskDAO {
             throw new IllegalArgumentException(type + " is not related to notifications");
         }
 
-        StringBuilder queryString = buildFindAllQuery(type);
+        StringBuilder queryString = new StringBuilder("SELECT ").
+                append(AbstractTask.TABLE).
+                append(".id FROM ").
+                append(AbstractTask.TABLE);
+        if (orderByTaskExecInfo) {
+            queryString.append(" LEFT OUTER JOIN ").
+                    append(JPATaskExec.TABLE).
+                    append(" ON ").
+                    append(AbstractTask.TABLE).
+                    append(".id = ").
+                    append(JPATaskExec.TABLE).
+                    append(".task_id");
+        }
+        queryString.append(" WHERE ").
+                append(AbstractTask.TABLE).
+                append(".DTYPE = ?1");
+        queryParameters.add(getEntityTableName(type));
+        if (type == TaskType.SCHEDULED) {
+            queryString.append(" AND ").
+                    append(AbstractTask.TABLE).
+                    append(".id NOT IN (SELECT ").append(AbstractTask.TABLE).append(".id
FROM ").
+                    append(AbstractTask.TABLE).append(" WHERE ").
+                    append(AbstractTask.TABLE).append(".DTYPE = ?2)").
+                    append(" AND ").
+                    append(AbstractTask.TABLE).
+                    append(".id NOT IN (SELECT id FROM ").
+                    append(AbstractTask.TABLE).append(" WHERE ").
+                    append(AbstractTask.TABLE).append(".DTYPE = ?3)");
+
+            queryParameters.add(JPAPushTask.class.getAnnotation(DiscriminatorValue.class).value());
+            queryParameters.add(JPAPullTask.class.getAnnotation(DiscriminatorValue.class).value());
+        }
+        queryString.append(' ');
 
         if (resource != null) {
-            queryString.append("AND t.resource=:resource ");
+            queryParameters.add(resource.getKey());
+
+            queryString.append("AND ").
+                    append(AbstractTask.TABLE).
+                    append(".resource_id=?").append(queryParameters.size());
         }
         if (notification != null) {
-            queryString.append("AND t.notification=:notification ");
+            queryParameters.add(notification.getKey());
+
+            queryString.append("AND ").
+                    append(AbstractTask.TABLE).
+                    append(".notification_id=?").append(queryParameters.size());
         }
         if (anyTypeKind != null && entityKey != null) {
-            queryString.append("AND t.anyTypeKind=:anyTypeKind AND t.entityKey=:entityKey
");
+            queryParameters.add(anyTypeKind.name());
+            queryParameters.add(entityKey);
+
+            queryString.append("AND ").
+                    append(AbstractTask.TABLE).
+                    append(".anyTypeKind=?").append(queryParameters.size() - 1).
+                    append(" AND ").
+                    append(AbstractTask.TABLE).
+                    append(".entityKey=?").append(queryParameters.size());
         }
 
         return queryString;
     }
 
     private String toOrderByStatement(
-            final Class<? extends Task> beanClass, final List<OrderByClause>
orderByClauses) {
+            final Class<? extends Task> beanClass,
+            final List<OrderByClause> orderByClauses,
+            final boolean orderByTaskExecInfo) {
 
         StringBuilder statement = new StringBuilder();
 
+        if (orderByTaskExecInfo) {
+            statement.append(" AND (").
+                    append(JPATaskExec.TABLE).
+                    append(".startDate IS NULL OR ").
+                    append(JPATaskExec.TABLE).
+                    append(".startDate = (SELECT MAX(").
+                    append(JPATaskExec.TABLE).
+                    append(".startDate) FROM ").
+                    append(JPATaskExec.TABLE).
+                    append(" WHERE ").
+                    append(AbstractTask.TABLE).
+                    append(".id = ").
+                    append(JPATaskExec.TABLE).
+                    append(".task_id))");
+        }
+        statement.append(" ORDER BY ");
+
+        StringBuilder subStatement = new StringBuilder();
         for (OrderByClause clause : orderByClauses) {
             String field = clause.getField().trim();
-            if (ReflectionUtils.findField(beanClass, field) != null) {
-                statement.append("t.").append(field).append(' ').append(clause.getDirection().name());
+            String table = JPATaskExec.TABLE;
+            switch (field) {
+                case "latestExecStatus":
+                    field = "status";
+                    break;
+
+                case "start":
+                    field = "startDate";
+                    break;
+
+                case "end":
+                    field = "endDate";
+                    break;
+
+                default:
+                    Field beanField = ReflectionUtils.findField(beanClass, field);
+                    if (beanField != null
+                            && (beanField.getAnnotation(ManyToOne.class) != null
+                            || beanField.getAnnotation(OneToMany.class) != null)) {
+                        field += "_id";
+                    }
+                    table = AbstractTask.TABLE;
             }
+            subStatement.append(table).
+                    append(".").
+                    append(field).
+                    append(' ').
+                    append(clause.getDirection().name()).
+                    append(',');
         }
 
-        if (statement.length() == 0) {
-            statement.append("ORDER BY t.id DESC");
+        if (subStatement.length() == 0) {
+            statement.append(AbstractTask.TABLE).
+                    append(".id DESC");
         } else {
-            statement.insert(0, "ORDER BY ");
+            subStatement.deleteCharAt(subStatement.length() - 1);
+            statement.append(subStatement);
         }
+
         return statement.toString();
     }
 
@@ -191,19 +327,31 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO
{
             final int itemsPerPage,
             final List<OrderByClause> orderByClauses) {
 
-        StringBuilder queryString = buildFindAllQuery(type, resource, notification, anyTypeKind,
entityKey).
-                append(toOrderByStatement(getEntityReference(type), orderByClauses));
+        List<Object> queryParameters = new ArrayList<>();
 
-        Query query = entityManager().createQuery(queryString.toString());
-        if (resource != null) {
-            query.setParameter("resource", resource);
-        }
-        if (notification != null) {
-            query.setParameter("notification", notification);
-        }
-        if (anyTypeKind != null && entityKey != null) {
-            query.setParameter("anyTypeKind", anyTypeKind);
-            query.setParameter("entityKey", entityKey);
+        boolean orderByTaskExecInfo = IterableUtils.matchesAny(orderByClauses, new Predicate<OrderByClause>()
{
+
+            @Override
+            public boolean evaluate(final OrderByClause object) {
+                return object.getField().equals("start")
+                        || object.getField().equals("end")
+                        || object.getField().equals("latestExecStatus")
+                        || object.getField().equals("status");
+            }
+        });
+        StringBuilder queryString = buildFindAllQuery(type,
+                resource,
+                notification,
+                anyTypeKind,
+                entityKey,
+                orderByTaskExecInfo,
+                queryParameters).
+                append(toOrderByStatement(getEntityReference(type), orderByClauses, orderByTaskExecInfo));
+
+        Query query = entityManager().createNativeQuery(queryString.toString());
+
+        for (int i = 1; i <= queryParameters.size(); i++) {
+            query.setParameter(i, queryParameters.get(i - 1));
         }
 
         query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1));
@@ -212,7 +360,7 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO
{
             query.setMaxResults(itemsPerPage);
         }
 
-        return query.getResultList();
+        return buildResult(query.getResultList());
     }
 
     @Override
@@ -223,19 +371,18 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO
{
             final AnyTypeKind anyTypeKind,
             final String entityKey) {
 
-        StringBuilder queryString = buildFindAllQuery(type, resource, notification, anyTypeKind,
entityKey);
+        List<Object> queryParameters = new ArrayList<>();
 
-        Query query = entityManager().createQuery(StringUtils.replaceOnce(
-                queryString.toString(), "SELECT t", "SELECT COUNT(t)"));
-        if (resource != null) {
-            query.setParameter("resource", resource);
-        }
-        if (notification != null) {
-            query.setParameter("notification", notification);
-        }
-        if (anyTypeKind != null && entityKey != null) {
-            query.setParameter("anyTypeKind", anyTypeKind);
-            query.setParameter("entityKey", entityKey);
+        StringBuilder queryString =
+                buildFindAllQuery(type, resource, notification, anyTypeKind, entityKey, false,
queryParameters);
+
+        Query query = entityManager().createNativeQuery(StringUtils.replaceOnce(
+                queryString.toString(),
+                "SELECT " + AbstractTask.TABLE + ".id",
+                "SELECT COUNT(" + AbstractTask.TABLE + ".id)"));
+
+        for (int i = 1; i <= queryParameters.size(); i++) {
+            query.setParameter(i, queryParameters.get(i - 1));
         }
 
         return ((Number) query.getSingleResult()).intValue();
@@ -274,4 +421,24 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO
{
             }
         });
     }
+
+    private <T extends Task> List<T> buildResult(final List<Object> raw)
{
+        List<T> result = new ArrayList<>();
+
+        for (Object anyKey : raw) {
+            String actualKey = anyKey instanceof Object[]
+                    ? (String) ((Object[]) anyKey)[0]
+                    : ((String) anyKey);
+
+            @SuppressWarnings("unchecked")
+            T any = find(actualKey);
+            if (any == null) {
+                LOG.error("Could not find task with id {}, even if returned by native query",
actualKey);
+            } else if (!result.contains(any)) {
+                result.add(any);
+            }
+        }
+
+        return result;
+    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
index fc47959..e1e6f1a 100644
--- a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
+++ b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/outer/TaskTest.java
@@ -24,9 +24,11 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
@@ -59,164 +61,179 @@ import org.apache.syncope.core.provisioning.api.pushpull.PullActions;
 
 @Transactional("Master")
 public class TaskTest extends AbstractTest {
-    
+
     @Autowired
     private TaskDAO taskDAO;
-    
+
     @Autowired
     private TaskExecDAO taskExecDAO;
-    
+
     @Autowired
     private ExternalResourceDAO resourceDAO;
-    
+
     @Autowired
     private UserDAO userDAO;
-    
+
     @Test
     public void read() {
         PropagationTask task = taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c");
         assertNotNull(task);
-        
+
         assertNotNull(task.getExecs());
         assertFalse(task.getExecs().isEmpty());
         assertEquals(1, task.getExecs().size());
     }
-    
+
+    @Test
+    public void readMultipleOrderBy() {
+        List<OrderByClause> orderByClauses = new ArrayList<>();
+        OrderByClause clause1 = new OrderByClause();
+        clause1.setField("start");
+        OrderByClause clause2 = new OrderByClause();
+        clause2.setField("latestExecStatus");
+        OrderByClause clause3 = new OrderByClause();
+        clause3.setField("connObjectKey");
+        orderByClauses.add(clause1);
+        orderByClauses.add(clause2);
+        orderByClauses.add(clause3);
+        assertFalse(taskDAO.findAll(TaskType.PROPAGATION, null, null, null, null, -1, -1,
orderByClauses).isEmpty());
+    }
+
     @Test
     public void save() {
         ExternalResource resource = resourceDAO.find("ws-target-resource-1");
         assertNotNull(resource);
-        
+
         User user = userDAO.findByUsername("verdi");
         assertNotNull(user);
-        
+
         PropagationTask task = entityFactory.newEntity(PropagationTask.class);
         task.setResource(resource);
         task.setAnyTypeKind(AnyTypeKind.USER);
         task.setAnyType(AnyTypeKind.USER.name());
         task.setOperation(ResourceOperation.CREATE);
         task.setConnObjectKey("one@two.com");
-        
+
         Set<Attribute> attributes = new HashSet<>();
         attributes.add(AttributeBuilder.build("testAttribute", "testValue1", "testValue2"));
         attributes.add(AttributeBuilder.buildPassword("password".toCharArray()));
         task.setAttributes(attributes);
-        
+
         task = taskDAO.save(task);
         assertNotNull(task);
-        
+
         PropagationTask actual = taskDAO.find(task.getKey());
         assertEquals(task, actual);
-        
+
         taskDAO.flush();
-        
+
         resource = resourceDAO.find("ws-target-resource-1");
         assertTrue(taskDAO.findAll(
                 TaskType.PROPAGATION, resource, null, null, null, -1, -1, Collections.<OrderByClause>emptyList()).
                 contains(task));
     }
-    
+
     @Test
     public void addPropagationTaskExecution() {
         PropagationTask task = taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c");
         assertNotNull(task);
-        
+
         int executionNumber = task.getExecs().size();
-        
+
         TaskExec execution = entityFactory.newEntity(TaskExec.class);
         execution.setTask(task);
         execution.setStatus(PropagationTaskExecStatus.CREATED.name());
         execution.setStart(new Date());
         task.add(execution);
-        
+
         taskDAO.save(task);
         taskDAO.flush();
-        
+
         task = taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c");
         assertNotNull(task);
-        
+
         assertEquals(executionNumber + 1, task.getExecs().size());
     }
-    
+
     @Test
     public void addPullTaskExecution() {
         PullTask task = taskDAO.find("c41b9b71-9bfa-4f90-89f2-84787def4c5c");
         assertNotNull(task);
-        
+
         int executionNumber = task.getExecs().size();
-        
+
         TaskExec execution = entityFactory.newEntity(TaskExec.class);
         execution.setStatus("Text-free status");
         execution.setTask(task);
         execution.setStart(new Date());
         execution.setMessage("A message");
         task.add(execution);
-        
+
         taskDAO.save(task);
         taskDAO.flush();
-        
+
         task = taskDAO.find("c41b9b71-9bfa-4f90-89f2-84787def4c5c");
         assertNotNull(task);
-        
+
         assertEquals(executionNumber + 1, task.getExecs().size());
     }
-    
+
     @Test
     public void addPushTaskExecution() {
         PushTask task = taskDAO.find("af558be4-9d2f-4359-bf85-a554e6e90be1");
         assertNotNull(task);
-        
+
         int executionNumber = task.getExecs().size();
-        
+
         TaskExec execution = entityFactory.newEntity(TaskExec.class);
         execution.setStatus("Text-free status");
         execution.setTask(task);
         execution.setStart(new Date());
         execution.setMessage("A message");
         task.add(execution);
-        
+
         taskDAO.save(task);
         taskDAO.flush();
-        
+
         task = taskDAO.find("af558be4-9d2f-4359-bf85-a554e6e90be1");
         assertNotNull(task);
-        
+
         assertEquals(executionNumber + 1, task.getExecs().size());
     }
-    
+
     @Test
     public void deleteTask() {
         taskDAO.delete("1e697572-b896-484c-ae7f-0c8f63fcbc6c");
-        
+
         taskDAO.flush();
-        
+
         assertNull(taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c"));
         assertNull(taskExecDAO.find("e58ca1c7-178a-4012-8a71-8aa14eaf0655"));
     }
-    
+
     @Test
     public void deleteTaskExecution() {
         TaskExec execution = taskExecDAO.find("e58ca1c7-178a-4012-8a71-8aa14eaf0655");
         int executionNumber = execution.getTask().getExecs().size();
-        
+
         taskExecDAO.delete("e58ca1c7-178a-4012-8a71-8aa14eaf0655");
-        
+
         taskExecDAO.flush();
-        
+
         assertNull(taskExecDAO.find("e58ca1c7-178a-4012-8a71-8aa14eaf0655"));
-        
+
         PropagationTask task = taskDAO.find("1e697572-b896-484c-ae7f-0c8f63fcbc6c");
         assertEquals(task.getExecs().size(), executionNumber - 1);
     }
-    
+
     @Test
     public void savePullTask() {
         ExternalResource resource = resourceDAO.find("ws-target-resource-1");
         assertNotNull(resource);
-        
+
         AnyTemplatePullTask template = entityFactory.newEntity(AnyTemplatePullTask.class);
         template.set(new UserTO());
-        
+
         PullTask task = entityFactory.newEntity(PullTask.class);
         task.setName("savePullTask");
         task.setDescription("PullTask description");
@@ -235,7 +252,7 @@ public class TaskTest extends AbstractTest {
             exception = e;
         }
         assertNotNull(exception);
-        
+
         task.setCronExpression(null);
         // this save() fails because a PullTask requires a target resource
         exception = null;
@@ -245,7 +262,7 @@ public class TaskTest extends AbstractTest {
             exception = e;
         }
         assertNotNull(exception);
-        
+
         task.setResource(resource);
         task.getActionsClassNames().add(getClass().getName());
 
@@ -258,24 +275,24 @@ public class TaskTest extends AbstractTest {
             exception = e;
         }
         assertNotNull(exception);
-        
+
         task.getActionsClassNames().clear();
         task.getActionsClassNames().add(PullActions.class.getName());
         // this save() finally works
         task = taskDAO.save(task);
         assertNotNull(task);
-        
+
         PullTask actual = taskDAO.find(task.getKey());
         assertEquals(task, actual);
     }
-    
+
     @Test
     public void issueSYNCOPE144() {
         ExternalResource resource = resourceDAO.find("ws-target-resource-1");
         assertNotNull(resource);
-        
+
         PullTask task = entityFactory.newEntity(PullTask.class);
-        
+
         task.setResource(resource);
         task.setName("issueSYNCOPE144");
         task.setDescription("issueSYNCOPE144 Description");
@@ -284,22 +301,22 @@ public class TaskTest extends AbstractTest {
         task.getActionsClassNames().add(PullActions.class.getName());
         task.setMatchingRule(MatchingRule.UPDATE);
         task.setUnmatchingRule(UnmatchingRule.PROVISION);
-        
+
         task = taskDAO.save(task);
         assertNotNull(task);
-        
+
         PullTask actual = taskDAO.find(task.getKey());
         assertEquals(task, actual);
         assertEquals("issueSYNCOPE144", actual.getName());
         assertEquals("issueSYNCOPE144 Description", actual.getDescription());
-        
+
         actual.setName("issueSYNCOPE144_2");
         actual.setDescription("issueSYNCOPE144 Description_2");
-        
+
         actual = taskDAO.save(actual);
         assertNotNull(actual);
         assertEquals("issueSYNCOPE144_2", actual.getName());
         assertEquals("issueSYNCOPE144 Description_2", actual.getDescription());
     }
-    
+
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/bb508d9f/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
index f583d86..b1e650d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/PropagationTaskITCase.java
@@ -24,12 +24,17 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import org.apache.commons.collections4.IterableUtils;
 import org.apache.commons.collections4.Predicate;
 import org.apache.commons.lang3.SerializationUtils;
+import org.apache.syncope.common.lib.patch.AttrPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.TaskTO;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
+import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.lib.to.BulkAction;
 import org.apache.syncope.common.lib.to.ConnObjectTO;
 import org.apache.syncope.common.lib.to.PagedResult;
@@ -40,6 +45,7 @@ import org.apache.syncope.common.lib.to.ProvisionTO;
 import org.apache.syncope.common.lib.to.ResourceTO;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.PatchOperation;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.common.rest.api.beans.ExecuteQuery;
 import org.apache.syncope.common.rest.api.beans.ExecQuery;
@@ -196,4 +202,76 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
                 page(1).size(2).build());
         assertTrue(execs.getTotalCount() >= execs.getResult().size());
     }
+
+    @Test
+    public void issueSYNCOPE1288() {
+        // create a new user
+        UserTO userTO = UserITCase.getUniqueSampleTO("xxxyyy@xxx.xxx");
+        userTO.getResources().add(RESOURCE_NAME_LDAP);
+
+        userTO = createUser(userTO).getEntity();
+        assertNotNull(userTO);
+
+        // generate some PropagationTasks
+        for (int i = 0; i < 9; i++) {
+            UserPatch userPatch = new UserPatch();
+            userPatch.setKey(userTO.getKey());
+            userPatch.getPlainAttrs().add(new AttrPatch.Builder().operation(PatchOperation.ADD_REPLACE).
+                    attrTO(new AttrTO.Builder().schema("userId").value(
+                            "test" + getUUIDString() + i + "@test.com").build()).
+                    build());
+
+            userService.update(userPatch);
+        }
+
+        // ASC order
+        PagedResult<TaskTO> unorderedTasks = taskService.search(
+                new TaskQuery.Builder(TaskType.PROPAGATION).
+                        resource(RESOURCE_NAME_LDAP).
+                        entityKey(userTO.getKey()).
+                        anyTypeKind(AnyTypeKind.USER).
+                        page(1).
+                        size(10).
+                        build());
+        Collections.sort(unorderedTasks.getResult(), new Comparator<TaskTO>() {
+
+            @Override
+            public int compare(final TaskTO o1, final TaskTO o2) {
+                return o1.getStart().compareTo(o2.getStart());
+            }
+        });
+        assertNotNull(unorderedTasks);
+        assertFalse(unorderedTasks.getResult().isEmpty());
+        assertEquals(10, unorderedTasks.getResult().size());
+
+        PagedResult<TaskTO> orderedTasks = taskService.search(
+                new TaskQuery.Builder(TaskType.PROPAGATION).
+                        resource(RESOURCE_NAME_LDAP).
+                        entityKey(userTO.getKey()).
+                        anyTypeKind(AnyTypeKind.USER).
+                        page(1).
+                        size(10).
+                        orderBy("start").
+                        build());
+        assertNotNull(orderedTasks);
+        assertFalse(orderedTasks.getResult().isEmpty());
+        assertEquals(10, orderedTasks.getResult().size());
+
+        assertTrue(orderedTasks.getResult().equals(unorderedTasks.getResult()));
+
+        // DESC order
+        Collections.reverse(unorderedTasks.getResult());
+        orderedTasks = taskService.search(
+                new TaskQuery.Builder(TaskType.PROPAGATION).
+                        resource(RESOURCE_NAME_LDAP).
+                        entityKey(userTO.getKey()).
+                        anyTypeKind(AnyTypeKind.USER).
+                        page(1).
+                        size(10).
+                        orderBy("start DESC").
+                        build());
+
+        assertTrue(orderedTasks.getResult().equals(unorderedTasks.getResult()));
+    }
+
 }


Mime
View raw message