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 java.io.Serializable;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Optional;
25 import java.util.stream.Collectors;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.syncope.client.console.SyncopeWebApplication;
28 import org.apache.syncope.client.console.commons.RealmsUtils;
29 import org.apache.syncope.client.console.rest.RealmRestClient;
30 import org.apache.syncope.client.console.rest.TaskRestClient;
31 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel;
32 import org.apache.syncope.client.console.wizards.BaseAjaxWizardBuilder;
33 import org.apache.syncope.client.ui.commons.Constants;
34 import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
35 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
36 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
37 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
38 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
39 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
40 import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel;
41 import org.apache.syncope.common.lib.SyncopeConstants;
42 import org.apache.syncope.common.lib.to.MacroTaskTO;
43 import org.apache.syncope.common.lib.to.ProvisioningTaskTO;
44 import org.apache.syncope.common.lib.to.PullTaskTO;
45 import org.apache.syncope.common.lib.to.PushTaskTO;
46 import org.apache.syncope.common.lib.to.RealmTO;
47 import org.apache.syncope.common.lib.to.SchedTaskTO;
48 import org.apache.syncope.common.lib.types.MatchingRule;
49 import org.apache.syncope.common.lib.types.PullMode;
50 import org.apache.syncope.common.lib.types.TaskType;
51 import org.apache.syncope.common.lib.types.ThreadPoolSettings;
52 import org.apache.syncope.common.lib.types.UnmatchingRule;
53 import org.apache.wicket.PageReference;
54 import org.apache.wicket.ajax.AjaxRequestTarget;
55 import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
56 import org.apache.wicket.extensions.wizard.WizardModel;
57 import org.apache.wicket.extensions.wizard.WizardStep;
58 import org.apache.wicket.markup.html.WebMarkupContainer;
59 import org.apache.wicket.model.IModel;
60 import org.apache.wicket.model.PropertyModel;
61 import org.apache.wicket.model.util.ListModel;
62 import org.springframework.beans.PropertyAccessorFactory;
63
64 public class SchedTaskWizardBuilder<T extends SchedTaskTO> extends BaseAjaxWizardBuilder<T> {
65
66 private static final long serialVersionUID = 5945391813567245081L;
67
68 protected final TaskType type;
69
70 protected final RealmRestClient realmRestClient;
71
72 protected final TaskRestClient taskRestClient;
73
74 protected PushTaskWrapper wrapper;
75
76 protected CrontabPanel crontabPanel;
77
78 protected final boolean fullRealmsTree;
79
80 public SchedTaskWizardBuilder(
81 final TaskType type,
82 final T taskTO,
83 final RealmRestClient realmRestClient,
84 final TaskRestClient taskRestClient,
85 final PageReference pageRef) {
86
87 super(taskTO, pageRef);
88 this.type = type;
89 this.realmRestClient = realmRestClient;
90 this.taskRestClient = taskRestClient;
91 this.fullRealmsTree = SyncopeWebApplication.get().fullRealmsTree(realmRestClient);
92 }
93
94 @Override
95 protected Serializable onApplyInternal(final SchedTaskTO modelObject) {
96 if (modelObject instanceof PushTaskTO && wrapper != null) {
97 wrapper.fillFilterConditions();
98 }
99
100 modelObject.setCronExpression(crontabPanel.getCronExpression());
101 if (modelObject.getKey() == null) {
102 taskRestClient.create(type, modelObject);
103 } else {
104 taskRestClient.update(type, modelObject);
105 }
106 return modelObject;
107 }
108
109 @Override
110 protected WizardModel buildModelSteps(final SchedTaskTO modelObject, final WizardModel wizardModel) {
111 wizardModel.add(new Profile(modelObject));
112 if (modelObject instanceof PushTaskTO) {
113 wrapper = new PushTaskWrapper(PushTaskTO.class.cast(modelObject));
114 wizardModel.add(new PushTaskFilters(wrapper, pageRef));
115 }
116 wizardModel.add(new Schedule(modelObject));
117 return wizardModel;
118 }
119
120 protected List<String> searchRealms(final String realmQuery) {
121 return realmRestClient.search(fullRealmsTree
122 ? RealmsUtils.buildRootQuery()
123 : RealmsUtils.buildKeywordQuery(realmQuery)).
124 getResult().stream().map(RealmTO::getFullPath).collect(Collectors.toList());
125 }
126
127 protected class Profile extends WizardStep {
128
129 private static final long serialVersionUID = -3043839139187792810L;
130
131 protected final IModel<List<String>> taskJobDelegates = SyncopeWebApplication.get().
132 getImplementationInfoProvider().getTaskJobDelegates();
133
134 protected final IModel<List<String>> reconFilterBuilders = SyncopeWebApplication.get().
135 getImplementationInfoProvider().getReconFilterBuilders();
136
137 protected final IModel<List<String>> macroActions = SyncopeWebApplication.get().
138 getImplementationInfoProvider().getMacroActions();
139
140 protected final IModel<List<String>> pullActions = SyncopeWebApplication.get().
141 getImplementationInfoProvider().getPullActions();
142
143 protected final IModel<List<String>> pushActions = SyncopeWebApplication.get().
144 getImplementationInfoProvider().getPushActions();
145
146 protected Profile(final SchedTaskTO taskTO) {
147 AjaxTextFieldPanel name = new AjaxTextFieldPanel(
148 Constants.NAME_FIELD_NAME, Constants.NAME_FIELD_NAME,
149 new PropertyModel<>(taskTO, Constants.NAME_FIELD_NAME),
150 false);
151 name.addRequiredLabel();
152 name.setEnabled(true);
153 add(name);
154
155 AjaxTextFieldPanel description = new AjaxTextFieldPanel(
156 Constants.DESCRIPTION_FIELD_NAME, Constants.DESCRIPTION_FIELD_NAME,
157 new PropertyModel<>(taskTO, Constants.DESCRIPTION_FIELD_NAME), false);
158 description.setEnabled(true);
159 add(description);
160
161 AjaxCheckBoxPanel active = new AjaxCheckBoxPanel(
162 "active", "active", new PropertyModel<>(taskTO, "active"), false);
163 add(active);
164
165 AjaxDropDownChoicePanel<String> jobDelegate = new AjaxDropDownChoicePanel<>(
166 "jobDelegate", "jobDelegate", new PropertyModel<>(taskTO, "jobDelegate"), false);
167 jobDelegate.setChoices(taskJobDelegates.getObject());
168 jobDelegate.addRequiredLabel();
169 jobDelegate.setEnabled(taskTO.getKey() == null);
170 add(jobDelegate);
171
172 AutoCompleteSettings settings = new AutoCompleteSettings();
173 settings.setShowCompleteListOnFocusGain(fullRealmsTree);
174 settings.setShowListOnEmptyInput(fullRealmsTree);
175
176
177
178
179 WebMarkupContainer macroTaskSpecifics = new WebMarkupContainer("macroTaskSpecifics");
180 add(macroTaskSpecifics.setRenderBodyOnly(true));
181
182 AjaxSearchFieldPanel realm = new AjaxSearchFieldPanel(
183 "realm", "realm", new PropertyModel<>(taskTO, "realm"), settings) {
184
185 private static final long serialVersionUID = -6390474600233486704L;
186
187 @Override
188 protected Iterator<String> getChoices(final String input) {
189 return (RealmsUtils.checkInput(input)
190 ? searchRealms(input)
191 : List.<String>of()).iterator();
192 }
193 };
194 if (taskTO instanceof MacroTaskTO) {
195 realm.addRequiredLabel();
196 if (StringUtils.isBlank(MacroTaskTO.class.cast(taskTO).getRealm())) {
197
198 realm.setModelObject(SyncopeConstants.ROOT_REALM);
199 }
200 }
201 macroTaskSpecifics.add(realm);
202
203 macroTaskSpecifics.add(new AjaxDropDownChoicePanel<>(
204 "macroActions", "macroActions", new PropertyModel<>(taskTO, "macroActions"), false).
205 setChoices(macroActions));
206
207 AjaxCheckBoxPanel continueOnError = new AjaxCheckBoxPanel(
208 "continueOnError", "continueOnError", new PropertyModel<>(taskTO, "continueOnError"), false);
209 macroTaskSpecifics.add(continueOnError);
210
211 AjaxCheckBoxPanel saveExecs = new AjaxCheckBoxPanel(
212 "saveExecs", "saveExecs", new PropertyModel<>(taskTO, "saveExecs"), false);
213 macroTaskSpecifics.add(saveExecs);
214
215
216
217
218 WebMarkupContainer pullTaskSpecifics = new WebMarkupContainer("pullTaskSpecifics");
219 add(pullTaskSpecifics.setRenderBodyOnly(true));
220
221 boolean isFiltered = false;
222 if (taskTO instanceof PullTaskTO) {
223 isFiltered = PullTaskTO.class.cast(taskTO).getPullMode() == PullMode.FILTERED_RECONCILIATION;
224 } else {
225 pullTaskSpecifics.setEnabled(false).setVisible(false);
226 }
227
228 AjaxDropDownChoicePanel<PullMode> pullMode = new AjaxDropDownChoicePanel<>(
229 "pullMode", "pullMode", new PropertyModel<>(taskTO, "pullMode"), false);
230 pullMode.setChoices(List.of(PullMode.values()));
231 if (taskTO instanceof PullTaskTO) {
232 pullMode.addRequiredLabel();
233 }
234 pullMode.setNullValid(!(taskTO instanceof PullTaskTO));
235 pullTaskSpecifics.add(pullMode);
236
237 AjaxDropDownChoicePanel<String> reconFilterBuilder = new AjaxDropDownChoicePanel<>(
238 "reconFilterBuilder", "reconFilterBuilder",
239 new PropertyModel<>(taskTO, "reconFilterBuilder"), false);
240 reconFilterBuilder.setChoices(reconFilterBuilders.getObject());
241 reconFilterBuilder.setEnabled(isFiltered);
242 reconFilterBuilder.setRequired(isFiltered);
243 pullTaskSpecifics.add(reconFilterBuilder);
244
245 pullMode.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
246
247 private static final long serialVersionUID = -1107858522700306810L;
248
249 @Override
250 protected void onUpdate(final AjaxRequestTarget target) {
251 reconFilterBuilder.setEnabled(pullMode.getModelObject() == PullMode.FILTERED_RECONCILIATION);
252 reconFilterBuilder.setRequired(pullMode.getModelObject() == PullMode.FILTERED_RECONCILIATION);
253 target.add(reconFilterBuilder);
254 }
255 });
256
257 AjaxSearchFieldPanel destinationRealm =
258 new AjaxSearchFieldPanel("destinationRealm", "destinationRealm",
259 new PropertyModel<>(taskTO, "destinationRealm"), settings) {
260
261 private static final long serialVersionUID = -6390474600233486704L;
262
263 @Override
264 protected Iterator<String> getChoices(final String input) {
265 return (RealmsUtils.checkInput(input)
266 ? searchRealms(input)
267 : List.<String>of()).iterator();
268 }
269 };
270
271 if (taskTO instanceof PullTaskTO) {
272 destinationRealm.addRequiredLabel();
273 if (StringUtils.isBlank(PullTaskTO.class.cast(taskTO).getDestinationRealm())) {
274
275 destinationRealm.setModelObject(SyncopeConstants.ROOT_REALM);
276 }
277 }
278 pullTaskSpecifics.add(destinationRealm);
279
280 AjaxCheckBoxPanel remediation = new AjaxCheckBoxPanel(
281 "remediation", "remediation", new PropertyModel<>(taskTO, "remediation"), false);
282 pullTaskSpecifics.add(remediation);
283
284
285
286
287 WebMarkupContainer pushTaskSpecifics = new WebMarkupContainer("pushTaskSpecifics");
288 add(pushTaskSpecifics.setRenderBodyOnly(true));
289
290 if (!(taskTO instanceof PushTaskTO)) {
291 pushTaskSpecifics.setEnabled(false).setVisible(false);
292 }
293
294 AjaxSearchFieldPanel sourceRealm = new AjaxSearchFieldPanel(
295 "sourceRealm", "sourceRealm", new PropertyModel<>(taskTO, "sourceRealm"), settings) {
296
297 private static final long serialVersionUID = -6390474600233486704L;
298
299 @Override
300 protected Iterator<String> getChoices(final String input) {
301 return (RealmsUtils.checkInput(input)
302 ? searchRealms(input)
303 : List.<String>of()).iterator();
304 }
305 };
306
307 if (taskTO instanceof PushTaskTO) {
308 sourceRealm.addRequiredLabel();
309 }
310 pushTaskSpecifics.add(sourceRealm);
311
312
313
314
315 WebMarkupContainer provisioningTaskSpecifics = new WebMarkupContainer("provisioningTaskSpecifics");
316 add(provisioningTaskSpecifics.setOutputMarkupId(true));
317
318 if (taskTO instanceof ProvisioningTaskTO) {
319 jobDelegate.setEnabled(false).setVisible(false);
320 macroTaskSpecifics.setEnabled(false).setVisible(false);
321 } else if (taskTO instanceof MacroTaskTO) {
322 jobDelegate.setEnabled(false).setVisible(false);
323 provisioningTaskSpecifics.setEnabled(false).setVisible(false);
324 } else {
325 provisioningTaskSpecifics.setEnabled(false).setVisible(false);
326 macroTaskSpecifics.setEnabled(false).setVisible(false);
327 }
328
329 AjaxPalettePanel<String> actions = new AjaxPalettePanel.Builder<String>().
330 setAllowMoveAll(true).setAllowOrder(true).
331 build("actions",
332 new PropertyModel<>(taskTO, "actions"),
333 new ListModel<>(taskTO instanceof PushTaskTO
334 ? pushActions.getObject() : pullActions.getObject()));
335 provisioningTaskSpecifics.add(actions.setOutputMarkupId(true));
336
337 AjaxDropDownChoicePanel<MatchingRule> matchingRule = new AjaxDropDownChoicePanel<>(
338 "matchingRule", "matchingRule", new PropertyModel<>(taskTO, "matchingRule"), false);
339 matchingRule.setChoices(List.of(MatchingRule.values()));
340 provisioningTaskSpecifics.add(matchingRule);
341
342 AjaxDropDownChoicePanel<UnmatchingRule> unmatchingRule = new AjaxDropDownChoicePanel<>(
343 "unmatchingRule", "unmatchingRule", new PropertyModel<>(taskTO, "unmatchingRule"), false);
344 unmatchingRule.setChoices(List.of(UnmatchingRule.values()));
345 provisioningTaskSpecifics.add(unmatchingRule);
346
347 AjaxCheckBoxPanel performCreate = new AjaxCheckBoxPanel(
348 "performCreate", "performCreate", new PropertyModel<>(taskTO, "performCreate"), false);
349 provisioningTaskSpecifics.add(performCreate);
350
351 AjaxCheckBoxPanel performUpdate = new AjaxCheckBoxPanel(
352 "performUpdate", "performUpdate", new PropertyModel<>(taskTO, "performUpdate"), false);
353 provisioningTaskSpecifics.add(performUpdate);
354
355 AjaxCheckBoxPanel performDelete = new AjaxCheckBoxPanel(
356 "performDelete", "performDelete", new PropertyModel<>(taskTO, "performDelete"), false);
357 provisioningTaskSpecifics.add(performDelete);
358
359 AjaxCheckBoxPanel syncStatus = new AjaxCheckBoxPanel(
360 "syncStatus", "syncStatus", new PropertyModel<>(taskTO, "syncStatus"), false);
361 provisioningTaskSpecifics.add(syncStatus);
362
363
364 PropertyModel<ThreadPoolSettings> concurrentSettingsModel =
365 new PropertyModel<>(taskTO, "concurrentSettings");
366
367 AjaxCheckBoxPanel enableConcurrentSettings = new AjaxCheckBoxPanel(
368 "enableConcurrentSettings", "enableConcurrentSettings", new IModel<Boolean>() {
369
370 private static final long serialVersionUID = -7126718045816207110L;
371
372 @Override
373 public Boolean getObject() {
374 return concurrentSettingsModel.getObject() != null;
375 }
376
377 @Override
378 public void setObject(final Boolean object) {
379
380 }
381 });
382 provisioningTaskSpecifics.add(enableConcurrentSettings.
383 setVisible(taskTO instanceof ProvisioningTaskTO).setOutputMarkupId(true));
384
385 FieldPanel<Integer> corePoolSize = new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
386 "corePoolSize",
387 "corePoolSize",
388 Integer.class,
389 new ConcurrentSettingsValueModel(concurrentSettingsModel, "corePoolSize")).setRequired(true);
390 corePoolSize.setOutputMarkupPlaceholderTag(true).setOutputMarkupId(true);
391 corePoolSize.setVisible(taskTO instanceof ProvisioningTaskTO
392 ? concurrentSettingsModel.getObject() != null
393 : false);
394 provisioningTaskSpecifics.add(corePoolSize);
395
396 FieldPanel<Integer> maxPoolSize = new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
397 "maxPoolSize",
398 "maxPoolSize",
399 Integer.class,
400 new ConcurrentSettingsValueModel(concurrentSettingsModel, "maxPoolSize")).setRequired(true);
401 maxPoolSize.setOutputMarkupPlaceholderTag(true).setOutputMarkupId(true);
402 maxPoolSize.setVisible(taskTO instanceof ProvisioningTaskTO
403 ? concurrentSettingsModel.getObject() != null
404 : false);
405 provisioningTaskSpecifics.add(maxPoolSize);
406
407 FieldPanel<Integer> queueCapacity = new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
408 "queueCapacity",
409 "queueCapacity",
410 Integer.class,
411 new ConcurrentSettingsValueModel(concurrentSettingsModel, "queueCapacity")).setRequired(true);
412 queueCapacity.setOutputMarkupPlaceholderTag(true).setOutputMarkupId(true);
413 queueCapacity.setVisible(taskTO instanceof ProvisioningTaskTO
414 ? concurrentSettingsModel.getObject() != null
415 : false);
416 provisioningTaskSpecifics.add(queueCapacity);
417
418 enableConcurrentSettings.getField().add(
419 new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
420
421 private static final long serialVersionUID = -1107858522700306810L;
422
423 @Override
424 protected void onUpdate(final AjaxRequestTarget target) {
425 if (concurrentSettingsModel.getObject() == null) {
426 concurrentSettingsModel.setObject(new ThreadPoolSettings());
427 } else {
428 concurrentSettingsModel.setObject(null);
429 }
430
431 corePoolSize.setVisible(concurrentSettingsModel.getObject() != null);
432 maxPoolSize.setVisible(concurrentSettingsModel.getObject() != null);
433 queueCapacity.setVisible(concurrentSettingsModel.getObject() != null);
434
435 target.add(provisioningTaskSpecifics);
436 }
437 });
438 }
439 }
440
441 protected static class ConcurrentSettingsValueModel implements IModel<Integer> {
442
443 private static final long serialVersionUID = 8869612332790116116L;
444
445 private final PropertyModel<ThreadPoolSettings> concurrentSettingsModel;
446
447 private final String property;
448
449 public ConcurrentSettingsValueModel(
450 final PropertyModel<ThreadPoolSettings> concurrentSettingsModel,
451 final String property) {
452
453 this.concurrentSettingsModel = concurrentSettingsModel;
454 this.property = property;
455 }
456
457 @Override
458 public Integer getObject() {
459 return Optional.ofNullable(concurrentSettingsModel.getObject()).
460 map(s -> (Integer) PropertyAccessorFactory.forBeanPropertyAccess(s).getPropertyValue(property)).
461 orElse(null);
462 }
463
464 @Override
465 public void setObject(final Integer object) {
466 Optional.ofNullable(concurrentSettingsModel.getObject()).
467 ifPresent(s -> PropertyAccessorFactory.forBeanPropertyAccess(s).setPropertyValue(property, object));
468 }
469 }
470
471 protected class Schedule extends WizardStep {
472
473 private static final long serialVersionUID = -785981096328637758L;
474
475 protected Schedule(final SchedTaskTO taskTO) {
476 crontabPanel = new CrontabPanel(
477 "schedule", new PropertyModel<>(taskTO, "cronExpression"), taskTO.getCronExpression());
478 add(crontabPanel);
479 }
480 }
481 }