1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.console.tasks;
20
21 import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
22 import java.io.Serializable;
23 import java.time.Duration;
24 import java.time.temporal.ChronoUnit;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.List;
29 import org.apache.commons.lang3.SerializationUtils;
30 import org.apache.commons.lang3.tuple.Pair;
31 import org.apache.syncope.client.console.SyncopeConsoleSession;
32 import org.apache.syncope.client.console.commons.IdRepoConstants;
33 import org.apache.syncope.client.console.commons.TaskDataProvider;
34 import org.apache.syncope.client.console.pages.BasePage;
35 import org.apache.syncope.client.console.panels.MultilevelPanel;
36 import org.apache.syncope.client.console.rest.RealmRestClient;
37 import org.apache.syncope.client.console.rest.TaskRestClient;
38 import org.apache.syncope.client.console.wicket.ajax.IndicatorAjaxTimerBehavior;
39 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn;
40 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
41 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn;
42 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
43 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
44 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType;
45 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
46 import org.apache.syncope.client.console.widgets.JobActionPanel;
47 import org.apache.syncope.client.ui.commons.Constants;
48 import org.apache.syncope.client.ui.commons.panels.ModalPanel;
49 import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
50 import org.apache.syncope.common.lib.SyncopeClientException;
51 import org.apache.syncope.common.lib.to.AnyTO;
52 import org.apache.syncope.common.lib.to.JobTO;
53 import org.apache.syncope.common.lib.to.SchedTaskTO;
54 import org.apache.syncope.common.lib.to.TemplatableTO;
55 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
56 import org.apache.syncope.common.lib.types.TaskType;
57 import org.apache.wicket.Component;
58 import org.apache.wicket.PageReference;
59 import org.apache.wicket.ajax.AjaxRequestTarget;
60 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
61 import org.apache.wicket.event.Broadcast;
62 import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
63 import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
64 import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
65 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
66 import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
67 import org.apache.wicket.markup.html.WebPage;
68 import org.apache.wicket.markup.html.basic.Label;
69 import org.apache.wicket.markup.repeater.Item;
70 import org.apache.wicket.model.IModel;
71 import org.apache.wicket.model.Model;
72 import org.apache.wicket.model.StringResourceModel;
73 import org.apache.wicket.spring.injection.annot.SpringBean;
74
75
76
77
78
79
80 public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO>
81 extends TaskDirectoryPanel<T> implements ModalPanel {
82
83 private static final long serialVersionUID = 4984337552918213290L;
84
85 @SpringBean
86 protected RealmRestClient realmRestClient;
87
88 @SpringBean
89 protected TaskRestClient taskRestClient;
90
91 protected final TaskType taskType;
92
93 protected final T schedTaskTO;
94
95 protected final TaskStartAtTogglePanel startAt;
96
97 protected final TemplatesTogglePanel templates;
98
99 protected SchedTaskDirectoryPanel(
100 final String id,
101 final TaskRestClient restClient,
102 final BaseModal<?> baseModal,
103 final MultilevelPanel multiLevelPanelRef,
104 final TaskType taskType,
105 final T newTaskTO,
106 final PageReference pageRef,
107 final boolean wizardInModal) {
108
109 super(id, restClient, baseModal, multiLevelPanelRef, pageRef, wizardInModal);
110 this.taskType = taskType;
111 this.schedTaskTO = newTaskTO;
112
113 modal.size(Modal.Size.Large);
114
115 addNewItemPanelBuilder(new SchedTaskWizardBuilder<>(
116 taskType, schedTaskTO, realmRestClient, taskRestClient, pageRef), true);
117
118 MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.TASK_CREATE);
119
120 setFooterVisibility(false);
121
122 initResultTable();
123
124 container.add(new IndicatorAjaxTimerBehavior(Duration.of(10, ChronoUnit.SECONDS)) {
125
126 private static final long serialVersionUID = -4661303265651934868L;
127
128 @Override
129 protected void onTimer(final AjaxRequestTarget target) {
130 container.modelChanged();
131 target.add(container);
132 }
133 });
134
135 startAt = new TaskStartAtTogglePanel(container, pageRef);
136 addInnerObject(startAt);
137
138 templates = new TemplatesTogglePanel(getActualId(), this, pageRef) {
139
140 private static final long serialVersionUID = -8765794727538618705L;
141
142 @Override
143 protected Serializable onApplyInternal(
144 final TemplatableTO targetObject, final String type, final AnyTO anyTO) {
145
146 targetObject.getTemplates().put(type, anyTO);
147 restClient.update(taskType, SchedTaskTO.class.cast(targetObject));
148 return targetObject;
149 }
150 };
151 addInnerObject(templates);
152 }
153
154 protected List<IColumn<T, String>> getHeadingFieldColumns() {
155 List<IColumn<T, String>> columns = new ArrayList<>();
156
157 columns.add(new KeyPropertyColumn<>(
158 new StringResourceModel(Constants.KEY_FIELD_NAME, this), Constants.KEY_FIELD_NAME));
159
160 columns.add(new PropertyColumn<>(
161 new StringResourceModel(Constants.NAME_FIELD_NAME, this),
162 Constants.NAME_FIELD_NAME, Constants.NAME_FIELD_NAME));
163
164 return columns;
165 }
166
167 protected List<IColumn<T, String>> getTrailingFieldColumns() {
168 List<IColumn<T, String>> columns = new ArrayList<>();
169
170 columns.add(new DatePropertyColumn<>(
171 new StringResourceModel("lastExec", this), null, "lastExec"));
172
173 columns.add(new DatePropertyColumn<>(
174 new StringResourceModel("nextExec", this), null, "nextExec"));
175
176 columns.add(new PropertyColumn<>(
177 new StringResourceModel("latestExecStatus", this), "latestExecStatus", "latestExecStatus"));
178
179 columns.add(new BooleanPropertyColumn<>(
180 new StringResourceModel("active", this), "active", "active"));
181
182 columns.add(new AbstractColumn<>(new Model<>(""), "running") {
183
184 private static final long serialVersionUID = -4008579357070833846L;
185
186 @Override
187 public void populateItem(
188 final Item<ICellPopulator<T>> cellItem,
189 final String componentId,
190 final IModel<T> rowModel) {
191
192 Component panel;
193 try {
194 JobTO jobTO = restClient.getJob(rowModel.getObject().getKey());
195 panel = new JobActionPanel(componentId, jobTO, false, SchedTaskDirectoryPanel.this);
196 MetaDataRoleAuthorizationStrategy.authorize(
197 panel, WebPage.ENABLE,
198 String.format("%s,%s", IdRepoEntitlement.TASK_EXECUTE, IdRepoEntitlement.TASK_UPDATE));
199 } catch (Exception e) {
200 LOG.error("Could not get job for task {}", rowModel.getObject().getKey(), e);
201 panel = new Label(componentId, Model.of());
202 }
203 cellItem.add(panel);
204 }
205
206 @Override
207 public String getCssClass() {
208 return "running-col";
209 }
210 });
211
212 return columns;
213 }
214
215 protected List<IColumn<T, String>> getFieldColumns() {
216 List<IColumn<T, String>> columns = new ArrayList<>();
217
218 columns.addAll(getHeadingFieldColumns());
219
220 columns.add(new PropertyColumn<>(new StringResourceModel("jobDelegate", this), "jobDelegate", "jobDelegate") {
221
222 private static final long serialVersionUID = -3223917055078733093L;
223
224 @Override
225 public void populateItem(
226 final Item<ICellPopulator<T>> item,
227 final String componentId,
228 final IModel<T> rowModel) {
229
230 IModel<?> model = getDataModel(rowModel);
231 if (model != null && model.getObject() instanceof String) {
232 String value = String.class.cast(model.getObject());
233 if (value.length() > 20) {
234 item.add(new Label(componentId, new Model<>("..." + value.substring(value.length() - 17))));
235 } else {
236 item.add(new Label(componentId, getDataModel(rowModel)));
237 }
238 } else {
239 super.populateItem(item, componentId, rowModel);
240 }
241 }
242 });
243
244 columns.addAll(getTrailingFieldColumns());
245
246 return columns;
247 }
248
249 @Override
250 protected final List<IColumn<T, String>> getColumns() {
251 List<IColumn<T, String>> columns = new ArrayList<>();
252
253 columns.addAll(getFieldColumns());
254
255 return columns;
256 }
257
258 @Override
259 public ActionsPanel<T> getActions(final IModel<T> model) {
260 ActionsPanel<T> panel = super.getActions(model);
261 T taskTO = model.getObject();
262
263 panel.add(new ActionLink<>() {
264
265 private static final long serialVersionUID = -3722207913631435501L;
266
267 @Override
268 public void onClick(final AjaxRequestTarget target, final T ignore) {
269 SchedTaskDirectoryPanel.this.getTogglePanel().close(target);
270 viewTaskExecs(taskTO, target);
271 }
272 }, ActionLink.ActionType.VIEW_EXECUTIONS, IdRepoEntitlement.TASK_READ);
273
274 panel.add(new ActionLink<>() {
275
276 private static final long serialVersionUID = -3722207913631435501L;
277
278 @Override
279 public void onClick(final AjaxRequestTarget target, final T ignore) {
280 send(SchedTaskDirectoryPanel.this, Broadcast.EXACT,
281 new AjaxWizard.EditItemActionEvent<>(
282 restClient.readTask(taskType, model.getObject().getKey()),
283 target).setTitleModel(
284 new StringResourceModel("inner.task.edit",
285 SchedTaskDirectoryPanel.this,
286 Model.of(Pair.of(ActionLink.ActionType.EDIT, model.getObject())))));
287 }
288 }, ActionLink.ActionType.EDIT, IdRepoEntitlement.TASK_UPDATE);
289
290 panel.add(new ActionLink<>() {
291
292 private static final long serialVersionUID = -3722207913631435501L;
293
294 @Override
295 public void onClick(final AjaxRequestTarget target, final T ignore) {
296 SchedTaskDirectoryPanel.this.getTogglePanel().close(target);
297 final T clone = SerializationUtils.clone(model.getObject());
298 clone.setKey(null);
299 send(SchedTaskDirectoryPanel.this, Broadcast.EXACT,
300 new AjaxWizard.EditItemActionEvent<>(clone, target).setTitleModel(
301 new StringResourceModel("inner.task.clone",
302 SchedTaskDirectoryPanel.this,
303 Model.of(Pair.of(ActionLink.ActionType.CLONE, model.getObject())))));
304 }
305 }, ActionLink.ActionType.CLONE, IdRepoEntitlement.TASK_CREATE);
306
307 addFurtherActions(panel, model);
308
309 panel.add(new ActionLink<>() {
310
311 private static final long serialVersionUID = -3722207913631435501L;
312
313 @Override
314 public void onClick(final AjaxRequestTarget target, final T ignore) {
315 SchedTaskDirectoryPanel.this.getTogglePanel().close(target);
316 startAt.setExecutionDetail(model.getObject().getKey(), model.getObject().getName(), target);
317 startAt.toggle(target, true);
318 }
319 }, ActionLink.ActionType.EXECUTE, IdRepoEntitlement.TASK_EXECUTE);
320
321 panel.add(new ActionLink<>() {
322
323 private static final long serialVersionUID = -3722207913631435501L;
324
325 @Override
326 public void onClick(final AjaxRequestTarget target, final T ignore) {
327 try {
328 restClient.delete(taskType, taskTO.getKey());
329
330 SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
331 target.add(container);
332 SchedTaskDirectoryPanel.this.getTogglePanel().close(target);
333 } catch (SyncopeClientException e) {
334 LOG.error("While deleting propagation task {}", taskTO.getKey(), e);
335 SyncopeConsoleSession.get().onException(e);
336 }
337 ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
338 }
339 }, ActionLink.ActionType.DELETE, IdRepoEntitlement.TASK_DELETE, true);
340
341 return panel;
342 }
343
344 protected void addFurtherActions(final ActionsPanel<T> panel, final IModel<T> model) {
345 }
346
347 @Override
348 protected String paginatorRowsKey() {
349 return IdRepoConstants.PREF_SCHED_TASKS_PAGINATOR_ROWS;
350 }
351
352 @Override
353 protected Collection<ActionType> getBatches() {
354 List<ActionType> batches = new ArrayList<>();
355 batches.add(ActionType.DELETE);
356 batches.add(ActionType.EXECUTE);
357 batches.add(ActionType.DRYRUN);
358 return batches;
359 }
360
361 @Override
362 protected SchedTasksProvider<T> dataProvider() {
363 return new SchedTasksProvider<>(taskType, rows);
364 }
365
366 protected class SchedTasksProvider<T extends SchedTaskTO> extends TaskDataProvider<T> {
367
368 private static final long serialVersionUID = 4725679400450513556L;
369
370 public SchedTasksProvider(final TaskType taskType, final int paginatorRows) {
371 super(paginatorRows, taskType);
372 setSort(Constants.NAME_FIELD_NAME, SortOrder.ASCENDING);
373 }
374
375 @Override
376 public long size() {
377 return restClient.count(taskType);
378 }
379
380 @Override
381 public Iterator<T> iterator(final long first, final long count) {
382 int page = ((int) first / paginatorRows);
383 return restClient.<T>list(
384 taskType, (page < 0 ? 0 : page) + 1, paginatorRows, getSort()).
385 iterator();
386 }
387 }
388 }