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.policies;
20
21 import java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.stream.Collectors;
27 import org.apache.syncope.client.console.SyncopeConsoleSession;
28 import org.apache.syncope.client.console.SyncopeWebApplication;
29 import org.apache.syncope.client.console.panels.AbstractModalPanel;
30 import org.apache.syncope.client.console.rest.PolicyRestClient;
31 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
32 import org.apache.syncope.client.ui.commons.Constants;
33 import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
34 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
35 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
36 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
37 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
38 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
39 import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
40 import org.apache.syncope.client.ui.commons.panels.WizardModalPanel;
41 import org.apache.syncope.client.ui.commons.wizards.AbstractModalPanelBuilder;
42 import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
43 import org.apache.syncope.common.lib.policy.PolicyTO;
44 import org.apache.syncope.common.lib.types.BackOffStrategy;
45 import org.apache.syncope.common.lib.types.ConflictResolutionAction;
46 import org.apache.syncope.common.lib.types.PolicyType;
47 import org.apache.wicket.Application;
48 import org.apache.wicket.Component;
49 import org.apache.wicket.PageReference;
50 import org.apache.wicket.ajax.AjaxRequestTarget;
51 import org.apache.wicket.core.util.lang.PropertyResolver;
52 import org.apache.wicket.core.util.lang.PropertyResolverConverter;
53 import org.apache.wicket.markup.html.list.ListItem;
54 import org.apache.wicket.markup.html.list.ListView;
55 import org.apache.wicket.model.IModel;
56 import org.apache.wicket.model.LoadableDetachableModel;
57 import org.apache.wicket.model.PropertyModel;
58 import org.apache.wicket.model.util.ListModel;
59
60 public class PolicyModalPanelBuilder<T extends PolicyTO> extends AbstractModalPanelBuilder<T> {
61
62 private static final long serialVersionUID = 5945391813567245081L;
63
64 protected static class BackOffParamsModel<N extends Number> implements IModel<N> {
65
66 private static final long serialVersionUID = 28839546672164L;
67
68 protected final PropertyModel<String> backOffParamsModel;
69
70 protected final int index;
71
72 BackOffParamsModel(final PropertyModel<String> backOffParamsModel, final int index) {
73 this.backOffParamsModel = backOffParamsModel;
74 this.index = index;
75 }
76
77 @SuppressWarnings("unchecked")
78 @Override
79 public N getObject() {
80 String[] split = backOffParamsModel.getObject().split(";");
81 if (index >= split.length) {
82 return null;
83 }
84
85 return index == 2
86 ? (N) Double.valueOf(backOffParamsModel.getObject().split(";")[index])
87 : (N) Long.valueOf(backOffParamsModel.getObject().split(";")[index]);
88 }
89
90 @Override
91 public void setObject(final N object) {
92 String[] split = backOffParamsModel.getObject().split(";");
93 if (index < split.length) {
94 split[index] = object.toString();
95 backOffParamsModel.setObject(Arrays.stream(split).collect(Collectors.joining(";")));
96 }
97 }
98 }
99
100 protected final BaseModal<T> modal;
101
102 protected final PolicyType type;
103
104 protected final PolicyRestClient policyRestClient;
105
106 public PolicyModalPanelBuilder(
107 final PolicyType type,
108 final T policyTO,
109 final BaseModal<T> modal,
110 final PolicyRestClient policyRestClient,
111 final PageReference pageRef) {
112
113 super(policyTO, pageRef);
114
115 this.type = type;
116 this.modal = modal;
117 this.policyRestClient = policyRestClient;
118 }
119
120 @Override
121 public WizardModalPanel<T> build(final String id, final int index, final AjaxWizard.Mode mode) {
122 return new Profile(newModelObject(), modal, pageRef);
123 }
124
125 private class Profile extends AbstractModalPanel<T> {
126
127 private static final long serialVersionUID = -3043839139187792810L;
128
129 private final T policyTO;
130
131 private final LoadableDetachableModel<List<String>> resources = new LoadableDetachableModel<>() {
132
133 private static final long serialVersionUID = 5275935387613157437L;
134
135 @Override
136 protected List<String> load() {
137 return SyncopeWebApplication.get().getResourceProvider().get();
138 }
139 };
140
141 private final LoadableDetachableModel<List<String>> accessPolicyConfClasses = new LoadableDetachableModel<>() {
142
143 private static final long serialVersionUID = 5275935387613157437L;
144
145 @Override
146 protected List<String> load() {
147 return SyncopeWebApplication.get().getAccessPolicyConfProvider().get();
148 }
149 };
150
151 Profile(final T policyTO, final BaseModal<T> modal, final PageReference pageRef) {
152 super(modal, pageRef);
153 modal.setFormModel(policyTO);
154
155 this.policyTO = policyTO;
156
157 List<Component> fields = new ArrayList<>();
158
159 fields.add(new AjaxTextFieldPanel("field", Constants.NAME_FIELD_NAME,
160 new PropertyModel<>(policyTO, Constants.NAME_FIELD_NAME), false).setRequired(true));
161
162 switch (type) {
163 case ACCOUNT:
164 fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
165 "field",
166 "maxAuthenticationAttempts",
167 Integer.class,
168 new PropertyModel<>(policyTO, "maxAuthenticationAttempts")));
169
170 fields.add(new AjaxCheckBoxPanel(
171 "field",
172 "propagateSuspension",
173 new PropertyModel<>(policyTO, "propagateSuspension"),
174 false));
175
176 fields.add(new AjaxPalettePanel.Builder<String>().setName("passthroughResources").build(
177 "field",
178 new PropertyModel<>(policyTO, "passthroughResources"),
179 new ListModel<>(resources.getObject())));
180 break;
181
182 case PASSWORD:
183 fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
184 "field",
185 "historyLength",
186 Integer.class,
187 new PropertyModel<>(policyTO, "historyLength")));
188
189 fields.add(new AjaxCheckBoxPanel(
190 "field",
191 "allowNullPassword",
192 new PropertyModel<>(policyTO, "allowNullPassword"),
193 false));
194 break;
195
196 case PROPAGATION:
197 fields.add(new AjaxCheckBoxPanel(
198 "field",
199 "fetchAroundProvisioning",
200 new PropertyModel<>(policyTO, "fetchAroundProvisioning"),
201 false));
202
203 fields.add(new AjaxCheckBoxPanel(
204 "field",
205 "updateDelta",
206 new PropertyModel<>(policyTO, "updateDelta"),
207 false));
208
209 fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().min(1).build(
210 "field",
211 "maxAttempts",
212 Integer.class,
213 new PropertyModel<>(policyTO, "maxAttempts")));
214 AjaxDropDownChoicePanel<Serializable> backOffStrategy = new AjaxDropDownChoicePanel<>(
215 "field",
216 "backOffStrategy",
217 new PropertyModel<>(policyTO, "backOffStrategy")).
218 setChoices(List.of((Serializable[]) BackOffStrategy.values()));
219 fields.add(backOffStrategy);
220
221 PropertyModel<String> backOffParamsModel = new PropertyModel<>(policyTO, "backOffParams");
222
223 AjaxSpinnerFieldPanel<Long> initialInterval = new AjaxSpinnerFieldPanel.Builder<Long>().
224 min(1L).build(
225 "field",
226 "initialInterval",
227 Long.class,
228 new BackOffParamsModel<>(backOffParamsModel, 0));
229 fields.add(initialInterval.setOutputMarkupPlaceholderTag(true));
230 AjaxSpinnerFieldPanel<Long> maxInterval = new AjaxSpinnerFieldPanel.Builder<Long>().
231 min(1L).build(
232 "field",
233 "maxInterval",
234 Long.class,
235 new BackOffParamsModel<>(backOffParamsModel, 1));
236 fields.add(maxInterval.setOutputMarkupPlaceholderTag(true).setVisible(false));
237 AjaxSpinnerFieldPanel<Double> multiplier = new AjaxSpinnerFieldPanel.Builder<Double>().
238 min(1D).build(
239 "field",
240 "multiplier",
241 Double.class,
242 new BackOffParamsModel<>(backOffParamsModel, 2));
243 fields.add(multiplier.setOutputMarkupPlaceholderTag(true).setVisible(false));
244
245 showHide(backOffStrategy, initialInterval, maxInterval, multiplier);
246
247 backOffStrategy.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
248
249 private static final long serialVersionUID = -1107858522700306810L;
250
251 @Override
252 protected void onUpdate(final AjaxRequestTarget target) {
253 BackOffStrategy strategy = (BackOffStrategy) backOffStrategy.getField().getModelObject();
254 backOffParamsModel.setObject(strategy.getDefaultBackOffParams());
255
256 showHide(backOffStrategy, initialInterval, maxInterval, multiplier);
257
258 target.add(initialInterval);
259 target.add(maxInterval);
260 target.add(multiplier);
261 }
262 });
263 break;
264
265 case PULL:
266 case PUSH:
267 fields.add(new AjaxDropDownChoicePanel<>(
268 "field",
269 "conflictResolutionAction",
270 new PropertyModel<>(policyTO, "conflictResolutionAction")).
271 setChoices(List.of((Serializable[]) ConflictResolutionAction.values())));
272 break;
273
274 case ACCESS:
275 fields.add(new AjaxDropDownChoicePanel<>(
276 "field",
277 "conf",
278 new IModel<>() {
279
280 private static final long serialVersionUID = -6515946495655944432L;
281
282 @Override
283 public Serializable getObject() {
284 return Optional.ofNullable(PropertyResolver.getValue("conf", policyTO)).
285 map(obj -> obj.getClass().getName()).
286 orElse(null);
287 }
288
289 @Override
290 public void setObject(final Serializable object) {
291 Object conf = Optional.ofNullable(object).map(o -> {
292 try {
293 return Class.forName(object.toString()).getDeclaredConstructor().newInstance();
294 } catch (Exception e) {
295 LOG.error("Could not instantiate {}", object, e);
296 return null;
297 }
298 }).orElse(null);
299
300 PropertyResolverConverter prc = new PropertyResolverConverter(
301 Application.get().getConverterLocator(),
302 SyncopeConsoleSession.get().getLocale());
303 PropertyResolver.setValue(
304 "conf",
305 policyTO,
306 Optional.ofNullable(conf).orElse(null),
307 prc);
308 }
309 }).setChoices(accessPolicyConfClasses).setRequired(true));
310 break;
311
312 case ATTR_RELEASE:
313 fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().build(
314 "field",
315 "order",
316 Integer.class,
317 new PropertyModel<>(policyTO, "order")));
318 fields.add(new AjaxCheckBoxPanel(
319 "field",
320 "status",
321 new PropertyModel<>(policyTO, "status"),
322 false));
323 break;
324
325 case AUTH:
326 default:
327 }
328
329 add(new ListView<>("fields", fields) {
330
331 private static final long serialVersionUID = -9180479401817023838L;
332
333 @Override
334 protected void populateItem(final ListItem<Component> item) {
335 item.add(item.getModelObject());
336 }
337 });
338 }
339
340 private void showHide(
341 final AjaxDropDownChoicePanel<Serializable> backOffStrategy,
342 final AjaxSpinnerFieldPanel<Long> initialInterval,
343 final AjaxSpinnerFieldPanel<Long> maxInterval,
344 final AjaxSpinnerFieldPanel<Double> multiplier) {
345
346 BackOffStrategy strategy = (BackOffStrategy) backOffStrategy.getField().getModelObject();
347
348 switch (strategy) {
349 case EXPONENTIAL:
350 initialInterval.addLabel("initialInterval");
351 maxInterval.setVisible(true);
352 multiplier.setVisible(true);
353 break;
354
355 case RANDOM:
356 initialInterval.addLabel("initialInterval");
357 maxInterval.setVisible(true);
358 multiplier.setVisible(true);
359 break;
360
361 case FIXED:
362 default:
363 initialInterval.addLabel("period");
364 maxInterval.setVisible(false);
365 multiplier.setVisible(false);
366 }
367 }
368
369 @Override
370 public void onSubmit(final AjaxRequestTarget target) {
371 try {
372 if (policyTO.getKey() == null) {
373 policyRestClient.create(type, policyTO);
374 } else {
375 policyRestClient.update(type, policyTO);
376 }
377 SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
378 Profile.this.modal.close(target);
379 } catch (Exception e) {
380 LOG.error("While creating/updating policy", e);
381 SyncopeConsoleSession.get().onException(e);
382 }
383 ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
384 }
385 }
386 }