You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2021/08/18 08:45:30 UTC

[syncope] branch master updated (998d7ef -> 246f6ba)

This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git.


    from 998d7ef  Upgrading Nimbus JOSE JWT and SLF4J
     new 5ebfe4e  Upgrading greenmail and docker-maven-plugin
     new 246f6ba  [SYNCOPE-1641] New REST endpoint to purge Propagation Tasks

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../common/rest/api/service/TaskService.java       |  20 ++++
 .../org/apache/syncope/core/logic/TaskLogic.java   |   6 ++
 .../core/rest/cxf/service/TaskServiceImpl.java     |  12 +++
 .../syncope/core/persistence/api/dao/TaskDAO.java  |   4 +
 .../core/persistence/jpa/dao/JPATaskDAO.java       | 105 ++++++++++++++++-----
 .../syncope/fit/core/PropagationTaskITCase.java    |  23 +++++
 pom.xml                                            |   4 +-
 7 files changed, 147 insertions(+), 27 deletions(-)

[syncope] 01/02: Upgrading greenmail and docker-maven-plugin

Posted by il...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 5ebfe4efbd71bd1d314b66d140ca901ae6cffb96
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Mon Aug 16 14:49:50 2021 +0200

    Upgrading greenmail and docker-maven-plugin
---
 pom.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index 0b50011..968a0d8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1158,7 +1158,7 @@ under the License.
       <dependency>
         <groupId>com.icegreen</groupId>
         <artifactId>greenmail</artifactId>
-        <version>1.6.4</version>
+        <version>1.6.5</version>
         <exclusions>
           <exclusion>
             <groupId>junit</groupId>
@@ -2247,7 +2247,7 @@ under the License.
         <plugin>
           <groupId>io.fabric8</groupId>
           <artifactId>docker-maven-plugin</artifactId>
-          <version>0.36.1</version>
+          <version>0.37.0</version>
         </plugin>
 
         <plugin>

[syncope] 02/02: [SYNCOPE-1641] New REST endpoint to purge Propagation Tasks

Posted by il...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit 246f6bac562c6dfe6e04889f04c87b9c8fbc7fbd
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Wed Aug 18 10:28:10 2021 +0200

    [SYNCOPE-1641] New REST endpoint to purge Propagation Tasks
---
 .../common/rest/api/service/TaskService.java       |  20 ++++
 .../org/apache/syncope/core/logic/TaskLogic.java   |   6 ++
 .../core/rest/cxf/service/TaskServiceImpl.java     |  12 +++
 .../syncope/core/persistence/api/dao/TaskDAO.java  |   4 +
 .../core/persistence/jpa/dao/JPATaskDAO.java       | 105 ++++++++++++++++-----
 .../syncope/fit/core/PropagationTaskITCase.java    |  23 +++++
 6 files changed, 145 insertions(+), 25 deletions(-)

diff --git a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/TaskService.java b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/TaskService.java
index 07a18d8..92ab611 100644
--- a/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/TaskService.java
+++ b/common/idrepo/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/TaskService.java
@@ -27,6 +27,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses;
 import io.swagger.v3.oas.annotations.security.SecurityRequirement;
 import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
+import java.util.Date;
+import java.util.List;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.BeanParam;
 import javax.ws.rs.Consumes;
@@ -45,6 +47,7 @@ import javax.ws.rs.core.Response;
 import org.apache.syncope.common.lib.to.TaskTO;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.types.ExecStatus;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.beans.TaskQuery;
@@ -138,4 +141,21 @@ public interface TaskService extends ExecutableService {
     @Path("{type}/{key}")
     @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
     void delete(@NotNull @PathParam("type") TaskType type, @NotNull @PathParam("key") String key);
+
+    /**
+     * Deletes all the propagation tasks whose latest execution is matching the given conditions.
+     * At least one matching condition must be specified.
+     *
+     * @param since
+     * @param statuses execution status(es) to match
+     * @return deleted propagation tasks
+     */
+    @ApiResponses({
+        @ApiResponse(responseCode = "200", description = "List of deleted propagation tasks, as Entity"),
+        @ApiResponse(responseCode = "412", description = "At least one matching condition must be specified") })
+    @DELETE
+    @Path("PROPAGATION/purge")
+    @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML })
+    Response purgePropagations(
+            @QueryParam("since") Date since, @QueryParam("statuses") List<ExecStatus> statuses);
 }
diff --git a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
index 57dd2bc..8b6c92e 100644
--- a/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
+++ b/core/idrepo/logic/src/main/java/org/apache/syncope/core/logic/TaskLogic.java
@@ -37,6 +37,7 @@ import org.apache.syncope.common.lib.to.PropagationTaskTO;
 import org.apache.syncope.common.lib.to.SchedTaskTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
+import org.apache.syncope.common.lib.types.ExecStatus;
 import org.apache.syncope.common.lib.types.JobAction;
 import org.apache.syncope.common.lib.types.JobType;
 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
@@ -454,6 +455,11 @@ public class TaskLogic extends AbstractExecutableLogic<TaskTO> {
         doActionJob(JobNamer.getJobKey(task), action);
     }
 
+    @PreAuthorize("hasRole('" + IdRepoEntitlement.TASK_DELETE + "')")
+    public List<PropagationTaskTO> purgePropagations(final Date since, final List<ExecStatus> statuses) {
+        return taskDAO.purgePropagations(since, statuses);
+    }
+
     @Override
     protected TaskTO resolveReference(final Method method, final Object... args)
             throws UnresolvedReferenceException {
diff --git a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java
index cd48508..6efb30f 100644
--- a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java
+++ b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/TaskServiceImpl.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.core.rest.cxf.service;
 
 import java.net.URI;
+import java.util.Date;
 import java.util.List;
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.core.Response;
@@ -26,6 +27,7 @@ import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.to.TaskTO;
 import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.SchedTaskTO;
+import org.apache.syncope.common.lib.types.ExecStatus;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.common.rest.api.beans.TaskQuery;
@@ -34,6 +36,7 @@ import org.apache.syncope.core.logic.AbstractExecutableLogic;
 import org.apache.syncope.core.logic.TaskLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
 
 @Service
 public class TaskServiceImpl extends AbstractExecutableService implements TaskService {
@@ -91,4 +94,13 @@ public class TaskServiceImpl extends AbstractExecutableService implements TaskSe
     public void update(final TaskType type, final SchedTaskTO taskTO) {
         logic.updateSchedTask(type, taskTO);
     }
+
+    @Override
+    public Response purgePropagations(final Date since, final List<ExecStatus> statuses) {
+        if (since == null && CollectionUtils.isEmpty(statuses)) {
+            return Response.status(Response.Status.PRECONDITION_FAILED).build();
+        }
+
+        return Response.ok(logic.purgePropagations(since, statuses)).build();
+    }
 }
diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/TaskDAO.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/TaskDAO.java
index f619154..7161479 100644
--- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/TaskDAO.java
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/TaskDAO.java
@@ -18,8 +18,11 @@
  */
 package org.apache.syncope.core.persistence.api.dao;
 
+import java.util.Date;
 import java.util.List;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ExecStatus;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.Implementation;
@@ -73,4 +76,5 @@ public interface TaskDAO extends DAO<Task> {
 
     void deleteAll(ExternalResource resource, TaskType type);
 
+    List<PropagationTaskTO> purgePropagations(Date since, List<ExecStatus> statuses);
 }
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 416412f..7ab1ade 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
@@ -20,14 +20,18 @@ package org.apache.syncope.core.persistence.jpa.dao;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 import javax.persistence.DiscriminatorValue;
 import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.Query;
 import javax.persistence.TypedQuery;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.ExecStatus;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.core.persistence.api.dao.RemediationDAO;
 import org.apache.syncope.core.persistence.api.dao.TaskDAO;
@@ -36,6 +40,7 @@ import org.apache.syncope.core.persistence.api.entity.Entity;
 import org.apache.syncope.core.persistence.api.entity.Implementation;
 import org.apache.syncope.core.persistence.api.entity.Notification;
 import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
+import org.apache.syncope.core.persistence.api.entity.task.PropagationTask;
 import org.apache.syncope.core.persistence.api.entity.task.PullTask;
 import org.apache.syncope.core.persistence.api.entity.task.PushTask;
 import org.apache.syncope.core.persistence.api.entity.task.SchedTask;
@@ -50,6 +55,7 @@ import org.apache.syncope.core.persistence.jpa.entity.task.JPATaskExec;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
 import org.springframework.util.ReflectionUtils;
 
 @Repository
@@ -206,13 +212,13 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO {
     }
 
     private static StringBuilder buildFindAllQuery(
-        final TaskType type,
-        final ExternalResource resource,
-        final Notification notification,
-        final AnyTypeKind anyTypeKind,
-        final String entityKey,
-        final boolean orderByTaskExecInfo,
-        final List<Object> queryParameters) {
+            final TaskType type,
+            final ExternalResource resource,
+            final Notification notification,
+            final AnyTypeKind anyTypeKind,
+            final String entityKey,
+            final boolean orderByTaskExecInfo,
+            final List<Object> queryParameters) {
 
         if (resource != null
                 && type != TaskType.PROPAGATION && type != TaskType.PUSH && type != TaskType.PULL) {
@@ -299,8 +305,9 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO {
         return queryString;
     }
 
-    private static String toOrderByStatement(final Class<? extends Task> beanClass,
-                                             final List<OrderByClause> orderByClauses) {
+    private static String toOrderByStatement(
+            final Class<? extends Task> beanClass,
+            final List<OrderByClause> orderByClauses) {
 
         StringBuilder statement = new StringBuilder();
 
@@ -345,7 +352,6 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
     public <T extends Task> List<T> findAll(
             final TaskType type,
             final ExternalResource resource,
@@ -405,7 +411,23 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO {
             query.setMaxResults(itemsPerPage);
         }
 
-        return buildResult(query.getResultList());
+        List<T> result = new ArrayList<>();
+
+        @SuppressWarnings("unchecked")
+        List<Object> raw = query.getResultList();
+        raw.stream().map(key -> key instanceof Object[]
+                ? (String) ((Object[]) key)[0]
+                : ((String) key)).forEach(key -> {
+
+            T task = find(key);
+            if (task == null) {
+                LOG.error("Could not find task with key {}, even if returned by native query", key);
+            } else if (!result.contains(task)) {
+                result.add(task);
+            }
+        });
+
+        return result;
     }
 
     @Override
@@ -464,23 +486,56 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO {
                 stream().map(Entity::getKey).forEach(this::delete);
     }
 
-    private <T extends Task> List<T> buildResult(final List<Object> raw) {
-        List<T> result = new ArrayList<>();
+    @Override
+    public List<PropagationTaskTO> purgePropagations(final Date since, final List<ExecStatus> statuses) {
+        StringBuilder queryString = new StringBuilder("SELECT t.task_id "
+                + "FROM TaskExec t INNER JOIN Task z ON t.task_id=z.id AND z.dtype='PropagationTask' "
+                + "WHERE t.enddate=(SELECT MAX(e.enddate) FROM TaskExec e WHERE e.task_id=t.task_id) ");
 
-        for (Object anyKey : raw) {
-            String actualKey = anyKey instanceof Object[]
-                    ? (String) ((Object[]) anyKey)[0]
-                    : ((String) anyKey);
+        List<Object> queryParameters = new ArrayList<>();
+        if (since != null) {
+            queryParameters.add(since);
+            queryString.append("AND t.enddate <= ?").append(queryParameters.size()).append(' ');
+        }
+        if (!CollectionUtils.isEmpty(statuses)) {
+            queryString.append("AND (").
+                    append(statuses.stream().map(status -> {
+                        queryParameters.add(status.name());
+                        return "t.status = ?" + queryParameters.size();
+                    }).collect(Collectors.joining(" OR "))).
+                    append(")");
+        }
 
-            @SuppressWarnings("unchecked")
-            T task = find(actualKey);
-            if (task == null) {
-                LOG.error("Could not find task with id {}, even if returned by native query", actualKey);
-            } else if (!result.contains(task)) {
-                result.add(task);
-            }
+        Query query = entityManager().createNativeQuery(queryString.toString());
+        for (int i = 1; i <= queryParameters.size(); i++) {
+            query.setParameter(i, queryParameters.get(i - 1));
         }
 
-        return result;
+        @SuppressWarnings("unchecked")
+        List<Object> raw = query.getResultList();
+
+        List<PropagationTaskTO> purged = new ArrayList<>();
+        raw.stream().map(Object::toString).distinct().forEach(key -> {
+            PropagationTask task = find(key);
+            if (task != null) {
+                PropagationTaskTO taskTO = new PropagationTaskTO();
+
+                taskTO.setOperation(task.getOperation());
+                taskTO.setConnObjectKey(task.getConnObjectKey());
+                taskTO.setOldConnObjectKey(task.getOldConnObjectKey());
+                taskTO.setAttributes(task.getSerializedAttributes());
+                taskTO.setResource(task.getResource().getKey());
+                taskTO.setObjectClassName(task.getObjectClassName());
+                taskTO.setAnyTypeKind(task.getAnyTypeKind());
+                taskTO.setAnyType(task.getAnyType());
+                taskTO.setEntityKey(task.getEntityKey());
+
+                purged.add(taskTO);
+
+                delete(task);
+            }
+        });
+
+        return purged;
     }
 }
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 b5acc24..a61a70e 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
@@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.IOException;
 import java.text.ParseException;
@@ -42,6 +43,8 @@ import org.apache.syncope.common.lib.request.UserUR;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.ws.rs.core.GenericType;
+import javax.xml.ws.WebServiceException;
 import org.apache.commons.lang3.SerializationUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
@@ -270,6 +273,26 @@ public class PropagationTaskITCase extends AbstractTaskITCase {
     }
 
     @Test
+    public void purgePropagations() {
+        try {
+            taskService.purgePropagations(null, null);
+            fail();
+        } catch (WebServiceException e) {
+            assertNotNull(e);
+        }
+
+        Calendar oneWeekAgo = Calendar.getInstance();
+        oneWeekAgo.add(Calendar.WEEK_OF_YEAR, -1);
+        Response response = taskService.purgePropagations(
+                oneWeekAgo.getTime(), Collections.singletonList(ExecStatus.SUCCESS));
+        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+
+        List<PropagationTaskTO> deleted = response.readEntity(new GenericType<List<PropagationTaskTO>>() {
+        });
+        assertNotNull(deleted);
+    }
+
+    @Test
     public void issueSYNCOPE741() {
         for (int i = 0; i < 3; i++) {
             taskService.execute(new ExecuteQuery.Builder().