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 public class Profile extends WizardStep {
128
129 private static final long serialVersionUID = -3043839139187792810L;
130
131 private final IModel<List<String>> taskJobDelegates = SyncopeWebApplication.get().
132 getImplementationInfoProvider().getTaskJobDelegates();
133
134 private final IModel<List<String>> reconFilterBuilders = SyncopeWebApplication.get().
135 getImplementationInfoProvider().getReconFilterBuilders();
136
137 private final IModel<List<String>> pullActions = SyncopeWebApplication.get().
138 getImplementationInfoProvider().getPullActions();
139
140 private final IModel<List<String>> pushActions = SyncopeWebApplication.get().
141 getImplementationInfoProvider().getPushActions();
142
143 public Profile(final SchedTaskTO taskTO) {
144 AjaxTextFieldPanel name = new AjaxTextFieldPanel(
145 Constants.NAME_FIELD_NAME, Constants.NAME_FIELD_NAME,
146 new PropertyModel<>(taskTO, Constants.NAME_FIELD_NAME),
147 false);
148 name.addRequiredLabel();
149 name.setEnabled(true);
150 add(name);
151
152 AjaxTextFieldPanel description = new AjaxTextFieldPanel(
153 Constants.DESCRIPTION_FIELD_NAME, Constants.DESCRIPTION_FIELD_NAME,
154 new PropertyModel<>(taskTO, Constants.DESCRIPTION_FIELD_NAME), false);
155 description.setEnabled(true);
156 add(description);
157
158 AjaxCheckBoxPanel active = new AjaxCheckBoxPanel(
159 "active", "active", new PropertyModel<>(taskTO, "active"), false);
160 add(active);
161
162 AjaxDropDownChoicePanel<String> jobDelegate = new AjaxDropDownChoicePanel<>(
163 "jobDelegate", "jobDelegate", new PropertyModel<>(taskTO, "jobDelegate"), false);
164 jobDelegate.setChoices(taskJobDelegates.getObject());
165 jobDelegate.addRequiredLabel();
166 jobDelegate.setEnabled(taskTO.getKey() == null);
167 add(jobDelegate);
168
169 AutoCompleteSettings settings = new AutoCompleteSettings();
170 settings.setShowCompleteListOnFocusGain(fullRealmsTree);
171 settings.setShowListOnEmptyInput(fullRealmsTree);
172
173
174
175
176 WebMarkupContainer macroTaskSpecifics = new WebMarkupContainer("macroTaskSpecifics");
177 add(macroTaskSpecifics.setRenderBodyOnly(true));
178
179 AjaxSearchFieldPanel realm =
180 new AjaxSearchFieldPanel("realm", "realm",
181 new PropertyModel<>(taskTO, "realm"), settings) {
182
183 private static final long serialVersionUID = -6390474600233486704L;
184
185 @Override
186 protected Iterator<String> getChoices(final String input) {
187 return (RealmsUtils.checkInput(input)
188 ? searchRealms(input)
189 : List.<String>of()).iterator();
190 }
191 };
192
193 if (taskTO instanceof MacroTaskTO) {
194 realm.addRequiredLabel();
195 if (StringUtils.isBlank(MacroTaskTO.class.cast(taskTO).getRealm())) {
196
197 realm.setModelObject(SyncopeConstants.ROOT_REALM);
198 }
199 }
200 macroTaskSpecifics.add(realm);
201
202 AjaxCheckBoxPanel continueOnError = new AjaxCheckBoxPanel(
203 "continueOnError", "continueOnError", new PropertyModel<>(taskTO, "continueOnError"), false);
204 macroTaskSpecifics.add(continueOnError);
205
206 AjaxCheckBoxPanel saveExecs = new AjaxCheckBoxPanel(
207 "saveExecs", "saveExecs", new PropertyModel<>(taskTO, "saveExecs"), false);
208 macroTaskSpecifics.add(saveExecs);
209
210
211
212
213 WebMarkupContainer pullTaskSpecifics = new WebMarkupContainer("pullTaskSpecifics");
214 add(pullTaskSpecifics.setRenderBodyOnly(true));
215
216 boolean isFiltered = false;
217 if (taskTO instanceof PullTaskTO) {
218 isFiltered = PullTaskTO.class.cast(taskTO).getPullMode() == PullMode.FILTERED_RECONCILIATION;
219 } else {
220 pullTaskSpecifics.setEnabled(false).setVisible(false);
221 }
222
223 AjaxDropDownChoicePanel<PullMode> pullMode = new AjaxDropDownChoicePanel<>(
224 "pullMode", "pullMode", new PropertyModel<>(taskTO, "pullMode"), false);
225 pullMode.setChoices(List.of(PullMode.values()));
226 if (taskTO instanceof PullTaskTO) {
227 pullMode.addRequiredLabel();
228 }
229 pullMode.setNullValid(!(taskTO instanceof PullTaskTO));
230 pullTaskSpecifics.add(pullMode);
231
232 AjaxDropDownChoicePanel<String> reconFilterBuilder = new AjaxDropDownChoicePanel<>(
233 "reconFilterBuilder", "reconFilterBuilder",
234 new PropertyModel<>(taskTO, "reconFilterBuilder"), false);
235 reconFilterBuilder.setChoices(reconFilterBuilders.getObject());
236 reconFilterBuilder.setEnabled(isFiltered);
237 reconFilterBuilder.setRequired(isFiltered);
238 pullTaskSpecifics.add(reconFilterBuilder);
239
240 pullMode.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
241
242 private static final long serialVersionUID = -1107858522700306810L;
243
244 @Override
245 protected void onUpdate(final AjaxRequestTarget target) {
246 reconFilterBuilder.setEnabled(
247 pullMode.getModelObject() == PullMode.FILTERED_RECONCILIATION);
248 reconFilterBuilder.setRequired(
249 pullMode.getModelObject() == PullMode.FILTERED_RECONCILIATION);
250 target.add(reconFilterBuilder);
251 }
252 });
253
254 AjaxSearchFieldPanel destinationRealm =
255 new AjaxSearchFieldPanel("destinationRealm", "destinationRealm",
256 new PropertyModel<>(taskTO, "destinationRealm"), settings) {
257
258 private static final long serialVersionUID = -6390474600233486704L;
259
260 @Override
261 protected Iterator<String> getChoices(final String input) {
262 return (RealmsUtils.checkInput(input)
263 ? searchRealms(input)
264 : List.<String>of()).iterator();
265 }
266 };
267
268 if (taskTO instanceof PullTaskTO) {
269 destinationRealm.addRequiredLabel();
270 if (StringUtils.isBlank(PullTaskTO.class.cast(taskTO).getDestinationRealm())) {
271
272 destinationRealm.setModelObject(SyncopeConstants.ROOT_REALM);
273 }
274 }
275 pullTaskSpecifics.add(destinationRealm);
276
277 AjaxCheckBoxPanel remediation = new AjaxCheckBoxPanel(
278 "remediation", "remediation", new PropertyModel<>(taskTO, "remediation"), false);
279 pullTaskSpecifics.add(remediation);
280
281
282
283
284 WebMarkupContainer pushTaskSpecifics = new WebMarkupContainer("pushTaskSpecifics");
285 add(pushTaskSpecifics.setRenderBodyOnly(true));
286
287 if (!(taskTO instanceof PushTaskTO)) {
288 pushTaskSpecifics.setEnabled(false).setVisible(false);
289 }
290
291 AjaxSearchFieldPanel sourceRealm = new AjaxSearchFieldPanel(
292 "sourceRealm", "sourceRealm", new PropertyModel<>(taskTO, "sourceRealm"), settings) {
293
294 private static final long serialVersionUID = -6390474600233486704L;
295
296 @Override
297 protected Iterator<String> getChoices(final String input) {
298 return (RealmsUtils.checkInput(input)
299 ? searchRealms(input)
300 : List.<String>of()).iterator();
301 }
302 };
303
304 if (taskTO instanceof PushTaskTO) {
305 sourceRealm.addRequiredLabel();
306 }
307 pushTaskSpecifics.add(sourceRealm);
308
309
310
311
312 WebMarkupContainer provisioningTaskSpecifics = new WebMarkupContainer("provisioningTaskSpecifics");
313 add(provisioningTaskSpecifics.setOutputMarkupId(true));
314
315 if (taskTO instanceof ProvisioningTaskTO) {
316 jobDelegate.setEnabled(false).setVisible(false);
317 macroTaskSpecifics.setEnabled(false).setVisible(false);
318 } else if (taskTO instanceof MacroTaskTO) {
319 jobDelegate.setEnabled(false).setVisible(false);
320 provisioningTaskSpecifics.setEnabled(false).setVisible(false);
321 } else {
322 provisioningTaskSpecifics.setEnabled(false).setVisible(false);
323 macroTaskSpecifics.setEnabled(false).setVisible(false);
324 }
325
326 AjaxPalettePanel<String> actions = new AjaxPalettePanel.Builder<String>().
327 setAllowMoveAll(true).setAllowOrder(true).
328 build("actions",
329 new PropertyModel<>(taskTO, "actions"),
330 new ListModel<>(taskTO instanceof PushTaskTO
331 ? pushActions.getObject() : pullActions.getObject()));
332 provisioningTaskSpecifics.add(actions.setOutputMarkupId(true));
333
334 AjaxDropDownChoicePanel<MatchingRule> matchingRule = new AjaxDropDownChoicePanel<>(
335 "matchingRule", "matchingRule", new PropertyModel<>(taskTO, "matchingRule"), false);
336 matchingRule.setChoices(List.of(MatchingRule.values()));
337 provisioningTaskSpecifics.add(matchingRule);
338
339 AjaxDropDownChoicePanel<UnmatchingRule> unmatchingRule = new AjaxDropDownChoicePanel<>(
340 "unmatchingRule", "unmatchingRule", new PropertyModel<>(taskTO, "unmatchingRule"),
341 false);
342 unmatchingRule.setChoices(List.of(UnmatchingRule.values()));
343 provisioningTaskSpecifics.add(unmatchingRule);
344
345 AjaxCheckBoxPanel performCreate = new AjaxCheckBoxPanel(
346 "performCreate", "performCreate", new PropertyModel<>(taskTO, "performCreate"), false);
347 provisioningTaskSpecifics.add(performCreate);
348
349 AjaxCheckBoxPanel performUpdate = new AjaxCheckBoxPanel(
350 "performUpdate", "performUpdate", new PropertyModel<>(taskTO, "performUpdate"), false);
351 provisioningTaskSpecifics.add(performUpdate);
352
353 AjaxCheckBoxPanel performDelete = new AjaxCheckBoxPanel(
354 "performDelete", "performDelete", new PropertyModel<>(taskTO, "performDelete"), false);
355 provisioningTaskSpecifics.add(performDelete);
356
357 AjaxCheckBoxPanel syncStatus = new AjaxCheckBoxPanel(
358 "syncStatus", "syncStatus", new PropertyModel<>(taskTO, "syncStatus"), false);
359 provisioningTaskSpecifics.add(syncStatus);
360
361
362 PropertyModel<ThreadPoolSettings> concurrentSettingsModel =
363 new PropertyModel<>(taskTO, "concurrentSettings");
364
365 AjaxCheckBoxPanel enableConcurrentSettings = new AjaxCheckBoxPanel(
366 "enableConcurrentSettings", "enableConcurrentSettings", new IModel<Boolean>() {
367
368 private static final long serialVersionUID = -7126718045816207110L;
369
370 @Override
371 public Boolean getObject() {
372 return concurrentSettingsModel.getObject() != null;
373 }
374
375 @Override
376 public void setObject(final Boolean object) {
377
378 }
379 });
380 provisioningTaskSpecifics.add(enableConcurrentSettings.
381 setVisible(taskTO instanceof ProvisioningTaskTO).setOutputMarkupId(true));
382
383 FieldPanel<Integer> corePoolSize = new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
384 "corePoolSize",
385 "corePoolSize",
386 Integer.class,
387 new ConcurrentSettingsValueModel(concurrentSettingsModel, "corePoolSize")).setRequired(true);
388 corePoolSize.setOutputMarkupPlaceholderTag(true).setOutputMarkupId(true);
389 corePoolSize.setVisible(taskTO instanceof ProvisioningTaskTO
390 ? concurrentSettingsModel.getObject() != null
391 : false);
392 provisioningTaskSpecifics.add(corePoolSize);
393
394 FieldPanel<Integer> maxPoolSize = new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
395 "maxPoolSize",
396 "maxPoolSize",
397 Integer.class,
398 new ConcurrentSettingsValueModel(concurrentSettingsModel, "maxPoolSize")).setRequired(true);
399 maxPoolSize.setOutputMarkupPlaceholderTag(true).setOutputMarkupId(true);
400 maxPoolSize.setVisible(taskTO instanceof ProvisioningTaskTO
401 ? concurrentSettingsModel.getObject() != null
402 : false);
403 provisioningTaskSpecifics.add(maxPoolSize);
404
405 FieldPanel<Integer> queueCapacity = new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
406 "queueCapacity",
407 "queueCapacity",
408 Integer.class,
409 new ConcurrentSettingsValueModel(concurrentSettingsModel, "queueCapacity")).setRequired(true);
410 queueCapacity.setOutputMarkupPlaceholderTag(true).setOutputMarkupId(true);
411 queueCapacity.setVisible(taskTO instanceof ProvisioningTaskTO
412 ? concurrentSettingsModel.getObject() != null
413 : false);
414 provisioningTaskSpecifics.add(queueCapacity);
415
416 enableConcurrentSettings.getField().add(
417 new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
418
419 private static final long serialVersionUID = -1107858522700306810L;
420
421 @Override
422 protected void onUpdate(final AjaxRequestTarget target) {
423 if (concurrentSettingsModel.getObject() == null) {
424 concurrentSettingsModel.setObject(new ThreadPoolSettings());
425 } else {
426 concurrentSettingsModel.setObject(null);
427 }
428
429 corePoolSize.setVisible(concurrentSettingsModel.getObject() != null);
430 maxPoolSize.setVisible(concurrentSettingsModel.getObject() != null);
431 queueCapacity.setVisible(concurrentSettingsModel.getObject() != null);
432
433 target.add(provisioningTaskSpecifics);
434 }
435 });
436 }
437 }
438
439 protected static class ConcurrentSettingsValueModel implements IModel<Integer> {
440
441 private static final long serialVersionUID = 8869612332790116116L;
442
443 private final PropertyModel<ThreadPoolSettings> concurrentSettingsModel;
444
445 private final String property;
446
447 public ConcurrentSettingsValueModel(
448 final PropertyModel<ThreadPoolSettings> concurrentSettingsModel,
449 final String property) {
450
451 this.concurrentSettingsModel = concurrentSettingsModel;
452 this.property = property;
453 }
454
455 @Override
456 public Integer getObject() {
457 return Optional.ofNullable(concurrentSettingsModel.getObject()).
458 map(s -> (Integer) PropertyAccessorFactory.forBeanPropertyAccess(s).getPropertyValue(property)).
459 orElse(null);
460 }
461
462 @Override
463 public void setObject(final Integer object) {
464 Optional.ofNullable(concurrentSettingsModel.getObject()).
465 ifPresent(s -> PropertyAccessorFactory.forBeanPropertyAccess(s).setPropertyValue(property, object));
466 }
467 }
468
469 public class Schedule extends WizardStep {
470
471 private static final long serialVersionUID = -785981096328637758L;
472
473 public Schedule(final SchedTaskTO taskTO) {
474 crontabPanel = new CrontabPanel(
475 "schedule", new PropertyModel<>(taskTO, "cronExpression"), taskTO.getCronExpression());
476 add(crontabPanel);
477 }
478 }
479 }