1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.persistence.jpa.dao;
20
21 import java.time.OffsetDateTime;
22 import java.util.ArrayList;
23 import java.util.Comparator;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.stream.Collectors;
27 import javax.persistence.Query;
28 import org.apache.syncope.common.lib.types.TaskType;
29 import org.apache.syncope.core.persistence.api.dao.TaskDAO;
30 import org.apache.syncope.core.persistence.api.dao.TaskExecDAO;
31 import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
32 import org.apache.syncope.core.persistence.api.entity.task.Task;
33 import org.apache.syncope.core.persistence.api.entity.task.TaskExec;
34 import org.apache.syncope.core.persistence.api.entity.task.TaskUtilsFactory;
35 import org.apache.syncope.core.persistence.jpa.entity.task.AbstractTaskExec;
36 import org.springframework.transaction.annotation.Transactional;
37 import org.springframework.util.ReflectionUtils;
38
39 public class JPATaskExecDAO extends AbstractDAO<TaskExec<?>> implements TaskExecDAO {
40
41 protected final TaskDAO taskDAO;
42
43 protected final TaskUtilsFactory taskUtilsFactory;
44
45 public JPATaskExecDAO(final TaskDAO taskDAO, final TaskUtilsFactory taskUtilsFactory) {
46 this.taskDAO = taskDAO;
47 this.taskUtilsFactory = taskUtilsFactory;
48 }
49
50 @SuppressWarnings("unchecked")
51 @Override
52 public <T extends Task<T>> TaskExec<T> find(final TaskType type, final String key) {
53 return (TaskExec<T>) entityManager().find(taskUtilsFactory.getInstance(type).getTaskExecEntity(), key);
54 }
55
56 @Override
57 public Optional<TaskExec<?>> find(final String key) {
58 TaskExec<?> task = find(TaskType.SCHEDULED, key);
59 if (task == null) {
60 task = find(TaskType.PULL, key);
61 }
62 if (task == null) {
63 task = find(TaskType.PUSH, key);
64 }
65 if (task == null) {
66 task = find(TaskType.MACRO, key);
67 }
68 if (task == null) {
69 task = find(TaskType.PROPAGATION, key);
70 }
71 if (task == null) {
72 task = find(TaskType.NOTIFICATION, key);
73 }
74
75 return Optional.ofNullable(task);
76 }
77
78 @SuppressWarnings("unchecked")
79 protected <T extends Task<T>> List<TaskExec<T>> findRecent(final TaskType type, final int max) {
80 Query query = entityManager().createQuery(
81 "SELECT e FROM " + taskUtilsFactory.getInstance(type).getTaskExecEntity().getSimpleName() + " e "
82 + "WHERE e.end IS NOT NULL ORDER BY e.end DESC");
83 query.setMaxResults(max);
84
85 List<Object> result = query.getResultList();
86 return result.stream().map(e -> (TaskExec<T>) e).collect(Collectors.toList());
87 }
88
89 @Override
90 public List<TaskExec<?>> findRecent(final int max) {
91 List<TaskExec<?>> recent = new ArrayList<>();
92
93 for (TaskType taskType : TaskType.values()) {
94 recent.addAll(findRecent(taskType, max));
95 }
96
97 return recent.stream().
98 sorted(Comparator.comparing(TaskExec<?>::getEnd).reversed()).
99 limit(max).
100 collect(Collectors.toList());
101 }
102
103 @SuppressWarnings("unchecked")
104 protected TaskExec<?> findLatest(final TaskType type, final Task<?> task, final String field) {
105 Query query = entityManager().createQuery(
106 "SELECT e FROM " + taskUtilsFactory.getInstance(type).getTaskExecEntity().getSimpleName() + " e "
107 + "WHERE e.task=:task ORDER BY e." + field + " DESC");
108 query.setParameter("task", task);
109 query.setMaxResults(1);
110
111 List<Object> result = query.getResultList();
112 return result == null || result.isEmpty()
113 ? null
114 : (TaskExec<?>) result.get(0);
115 }
116
117 @Override
118 public TaskExec<?> findLatestStarted(final TaskType type, final Task<?> task) {
119 return findLatest(type, task, "start");
120 }
121
122 @Override
123 public TaskExec<?> findLatestEnded(final TaskType type, final Task<?> task) {
124 return findLatest(type, task, "end");
125 }
126
127 protected StringBuilder query(
128 final StringBuilder select,
129 final Task<?> task,
130 final OffsetDateTime before,
131 final OffsetDateTime after) {
132
133 StringBuilder query = select.
134 append(taskUtilsFactory.getInstance(task).getTaskExecEntity().getSimpleName()).
135 append(" e WHERE e.task=:task ");
136 if (before != null) {
137 query.append("AND e.start <= :before ");
138 }
139 if (after != null) {
140 query.append("AND e.start >= :after ");
141 }
142 return query;
143 }
144
145 @Override
146 public int count(
147 final Task<?> task,
148 final OffsetDateTime before,
149 final OffsetDateTime after) {
150
151 StringBuilder queryString = query(new StringBuilder("SELECT COUNT(e) FROM "), task, before, after);
152
153 Query query = entityManager().createQuery(queryString.toString());
154 query.setParameter("task", task);
155 if (before != null) {
156 query.setParameter("before", before);
157 }
158 if (after != null) {
159 query.setParameter("after", after);
160 }
161
162 return ((Number) query.getSingleResult()).intValue();
163 }
164
165 protected String toOrderByStatement(final List<OrderByClause> orderByClauses) {
166 StringBuilder statement = new StringBuilder();
167
168 orderByClauses.forEach(clause -> {
169 String field = clause.getField().trim();
170 if (ReflectionUtils.findField(AbstractTaskExec.class, field) != null) {
171 statement.append("e.").append(field).append(' ').append(clause.getDirection().name());
172 }
173 });
174
175 if (statement.length() == 0) {
176 statement.append(" ORDER BY e.id DESC");
177 } else {
178 statement.insert(0, " ORDER BY ");
179 }
180 return statement.toString();
181 }
182
183 @SuppressWarnings("unchecked")
184 @Override
185 public List<TaskExec<?>> findAll(
186 final Task<?> task,
187 final OffsetDateTime before,
188 final OffsetDateTime after,
189 final int page,
190 final int itemsPerPage,
191 final List<OrderByClause> orderByClauses) {
192
193 StringBuilder queryString = query(new StringBuilder("SELECT e FROM "), task, before, after).
194 append(toOrderByStatement(orderByClauses));
195
196 Query query = entityManager().createQuery(queryString.toString());
197 query.setParameter("task", task);
198 if (before != null) {
199 query.setParameter("before", before);
200 }
201 if (after != null) {
202 query.setParameter("after", after);
203 }
204
205
206 query.setFirstResult(itemsPerPage * (page <= 0 ? 0 : page - 1));
207
208 if (itemsPerPage >= 0) {
209 query.setMaxResults(itemsPerPage);
210 }
211
212 List<Object> result = query.getResultList();
213 return result.stream().map(e -> (TaskExec<?>) e).collect(Collectors.toList());
214 }
215
216 @Transactional(rollbackFor = { Throwable.class })
217 @Override
218 public <T extends Task<T>> TaskExec<T> save(final TaskExec<T> execution) {
219 return entityManager().merge(execution);
220 }
221
222 @Transactional(rollbackFor = { Throwable.class })
223 @Override
224 public <T extends Task<T>> void saveAndAdd(
225 final TaskType taskType, final String taskKey, final TaskExec<T> execution) {
226
227 T task = taskDAO.find(taskType, taskKey);
228 task.add(execution);
229 taskDAO.save(task);
230 }
231
232 @Override
233 public <T extends Task<T>> void delete(final TaskType taskType, final String key) {
234 TaskExec<T> execution = find(taskType, key);
235 if (execution == null) {
236 return;
237 }
238
239 delete(execution);
240 }
241
242 @Override
243 public <T extends Task<T>> void delete(final TaskExec<T> execution) {
244 if (execution.getTask() != null) {
245 execution.getTask().getExecs().remove(execution);
246 }
247
248 entityManager().remove(execution);
249 }
250 }