View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.client.console.panels;
20  
21  import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
22  import java.util.ArrayList;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.stream.Collectors;
26  import org.apache.commons.lang3.BooleanUtils;
27  import org.apache.commons.lang3.StringUtils;
28  import org.apache.syncope.client.console.commons.PropertyList;
29  import org.apache.syncope.client.console.rest.ImplementationRestClient;
30  import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
31  import org.apache.syncope.client.ui.commons.Constants;
32  import org.apache.syncope.client.ui.commons.MIMETypesLoader;
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.AjaxTextFieldPanel;
37  import org.apache.syncope.common.lib.SyncopeConstants;
38  import org.apache.syncope.common.lib.to.ImplementationTO;
39  import org.apache.syncope.common.lib.to.PlainSchemaTO;
40  import org.apache.syncope.common.lib.types.AttrSchemaType;
41  import org.apache.syncope.common.lib.types.CipherAlgorithm;
42  import org.apache.syncope.common.lib.types.IdRepoImplementationType;
43  import org.apache.wicket.ajax.AjaxRequestTarget;
44  import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteTextField;
45  import org.apache.wicket.markup.html.WebMarkupContainer;
46  import org.apache.wicket.markup.html.form.DropDownChoice;
47  import org.apache.wicket.model.IModel;
48  import org.apache.wicket.model.LoadableDetachableModel;
49  import org.apache.wicket.model.Model;
50  import org.apache.wicket.model.PropertyModel;
51  import org.apache.wicket.spring.injection.annot.SpringBean;
52  import org.apache.wicket.util.string.Strings;
53  
54  public class PlainSchemaDetails extends AbstractSchemaDetailsPanel {
55  
56      private static final long serialVersionUID = 5378100729213456451L;
57  
58      @SpringBean
59      protected MIMETypesLoader mimeTypesLoader;
60  
61      @SpringBean
62      protected ImplementationRestClient implementationRestClient;
63  
64      protected final MultiFieldPanel<String> enumerationValues;
65  
66      protected final MultiFieldPanel<String> enumerationKeys;
67  
68      protected final AjaxDropDownChoicePanel<String> validator;
69  
70      protected final AjaxDropDownChoicePanel<AttrSchemaType> type;
71  
72      public PlainSchemaDetails(final String id, final PlainSchemaTO schemaTO) {
73          super(id, schemaTO);
74  
75          type = new AjaxDropDownChoicePanel<>("type", getString("type"), new PropertyModel<>(schemaTO, "type"));
76  
77          boolean isCreate = schemaTO == null || schemaTO.getKey() == null || schemaTO.getKey().isEmpty();
78  
79          type.setChoices(List.of(AttrSchemaType.values()));
80          type.setEnabled(isCreate);
81          type.addRequiredLabel();
82          add(type);
83  
84          // long, double, date
85          AjaxTextFieldPanel conversionPattern = new AjaxTextFieldPanel("conversionPattern",
86                  getString("conversionPattern"), new PropertyModel<>(schemaTO, "conversionPattern"));
87          add(conversionPattern);
88  
89          WebMarkupContainer conversionParams = new WebMarkupContainer("conversionParams");
90          conversionParams.setOutputMarkupPlaceholderTag(true);
91          conversionParams.add(conversionPattern);
92          add(conversionParams);
93  
94          WebMarkupContainer typeParams = new WebMarkupContainer("typeParams");
95          typeParams.setOutputMarkupPlaceholderTag(true);
96  
97          // enum
98          AjaxTextFieldPanel enumerationValuesPanel = new AjaxTextFieldPanel("panel",
99                  "enumerationValues", new Model<>(null));
100 
101         enumerationValues = new MultiFieldPanel.Builder<>(
102                 new PropertyModel<List<String>>(schemaTO, "enumerationValues") {
103 
104             private static final long serialVersionUID = -4953564762272833993L;
105 
106             @Override
107             public PropertyList<PlainSchemaTO> getObject() {
108                 return new PropertyList<>() {
109 
110                     @Override
111                     public String getValues() {
112                         return schemaTO.getEnumerationValues();
113                     }
114 
115                     @Override
116                     public void setValues(final List<String> list) {
117                         schemaTO.setEnumerationValues(getEnumValuesAsString(list));
118                     }
119                 };
120             }
121 
122             @Override
123             public void setObject(final List<String> object) {
124                 schemaTO.setEnumerationValues(PropertyList.getEnumValuesAsString(object));
125             }
126         }) {
127 
128             private static final long serialVersionUID = -8752965211744734798L;
129 
130             @Override
131             protected String newModelObject() {
132                 return StringUtils.EMPTY;
133             }
134 
135         }.build(
136                 "enumerationValues",
137                 "enumerationValues",
138                 enumerationValuesPanel);
139 
140         enumerationKeys = new MultiFieldPanel.Builder<String>(
141                 new PropertyModel<List<String>>(schemaTO, "enumerationKeys") {
142 
143             private static final long serialVersionUID = -4953564762272833993L;
144 
145             @Override
146             public PropertyList<PlainSchemaTO> getObject() {
147                 return new PropertyList<PlainSchemaTO>() {
148 
149                     @Override
150                     public String getValues() {
151                         return schemaTO.getEnumerationKeys();
152                     }
153 
154                     @Override
155                     public void setValues(final List<String> list) {
156                         schemaTO.setEnumerationKeys(PropertyList.getEnumValuesAsString(list));
157                     }
158                 };
159             }
160 
161             @Override
162             public void setObject(final List<String> object) {
163                 schemaTO.setEnumerationKeys(PropertyList.getEnumValuesAsString(object));
164             }
165         }) {
166 
167             private static final long serialVersionUID = -8752965211744734798L;
168 
169             @Override
170             protected String newModelObject() {
171                 return StringUtils.EMPTY;
172             }
173 
174         }.build(
175                 "enumerationKeys",
176                 "enumerationKeys",
177                 new AjaxTextFieldPanel("panel", "enumerationKeys", new Model<>(null)));
178 
179         WebMarkupContainer enumParams = new WebMarkupContainer("enumParams");
180         enumParams.setOutputMarkupPlaceholderTag(true);
181         enumParams.add(enumerationValues);
182         enumParams.add(enumerationKeys);
183         typeParams.add(enumParams);
184 
185         // encrypted
186         AjaxTextFieldPanel secretKey = new AjaxTextFieldPanel("secretKey",
187                 getString("secretKey"), new PropertyModel<>(schemaTO, "secretKey"));
188 
189         AjaxDropDownChoicePanel<CipherAlgorithm> cipherAlgorithm = new AjaxDropDownChoicePanel<>(
190                 "cipherAlgorithm", getString("cipherAlgorithm"),
191                 new PropertyModel<>(schemaTO, "cipherAlgorithm"));
192         cipherAlgorithm.setChoices(List.of(CipherAlgorithm.values()));
193 
194         AjaxCheckBoxPanel transparentEncryption = new AjaxCheckBoxPanel(
195                 "transparentEncryption", "transparentEncryption", new Model<Boolean>() {
196 
197             private static final long serialVersionUID = 5636572627689425575L;
198 
199             @Override
200             public Boolean getObject() {
201                 return SyncopeConstants.ENCRYPTED_DECODE_CONVERSION_PATTERN.equals(schemaTO.getConversionPattern());
202             }
203 
204             @Override
205             public void setObject(final Boolean object) {
206                 schemaTO.setConversionPattern(BooleanUtils.isTrue(object)
207                         ? SyncopeConstants.ENCRYPTED_DECODE_CONVERSION_PATTERN
208                         : null);
209             }
210         }, true);
211 
212         WebMarkupContainer encryptedParams = new WebMarkupContainer("encryptedParams");
213         encryptedParams.setOutputMarkupPlaceholderTag(true);
214         encryptedParams.add(secretKey);
215         encryptedParams.add(cipherAlgorithm);
216         encryptedParams.add(transparentEncryption);
217 
218         typeParams.add(encryptedParams);
219 
220         // binary
221         AjaxTextFieldPanel mimeType = new AjaxTextFieldPanel("mimeType",
222                 getString("mimeType"), new PropertyModel<>(schemaTO, "mimeType"));
223 
224         WebMarkupContainer binaryParams = new WebMarkupContainer("binaryParams");
225         binaryParams.setOutputMarkupPlaceholderTag(true);
226         binaryParams.add(mimeType);
227         typeParams.add(binaryParams);
228         add(typeParams);
229 
230         // show or hide
231         showHide(schemaTO, type,
232                 conversionParams, conversionPattern,
233                 enumParams, enumerationValuesPanel, enumerationValues, enumerationKeys,
234                 encryptedParams, secretKey, cipherAlgorithm,
235                 binaryParams, mimeType);
236 
237         type.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
238 
239             private static final long serialVersionUID = -1107858522700306810L;
240 
241             @Override
242             protected void onUpdate(final AjaxRequestTarget target) {
243                 PlainSchemaDetails.this.showHide(schemaTO, type,
244                         conversionParams, conversionPattern,
245                         enumParams, enumerationValuesPanel, enumerationValues, enumerationKeys,
246                         encryptedParams, secretKey, cipherAlgorithm,
247                         binaryParams, mimeType);
248                 target.add(conversionParams);
249                 target.add(typeParams);
250                 target.add(validator);
251             }
252         });
253 
254         IModel<List<String>> validators = new LoadableDetachableModel<List<String>>() {
255 
256             private static final long serialVersionUID = 5275935387613157437L;
257 
258             @Override
259             protected List<String> load() {
260                 return implementationRestClient.list(IdRepoImplementationType.VALIDATOR).stream().
261                         map(ImplementationTO::getKey).sorted().collect(Collectors.toList());
262             }
263         };
264         validator = new AjaxDropDownChoicePanel<>("validator",
265                 getString("validator"), new PropertyModel<>(schemaTO, "validator"));
266         validator.setOutputMarkupId(true);
267         ((DropDownChoice) validator.getField()).setNullValid(true);
268         validator.setChoices(validators.getObject());
269         add(validator);
270 
271         AutoCompleteTextField<String> mandatoryCondition = new AutoCompleteTextField<String>(
272                 "mandatoryCondition", new PropertyModel<>(schemaTO, "mandatoryCondition")) {
273 
274             private static final long serialVersionUID = -2428903969518079100L;
275 
276             @Override
277             protected Iterator<String> getChoices(final String input) {
278                 List<String> choices = new ArrayList<>();
279 
280                 if (Strings.isEmpty(input)) {
281                     choices = List.of();
282                 } else if ("true".startsWith(input.toLowerCase())) {
283                     choices.add("true");
284                 } else if ("false".startsWith(input.toLowerCase())) {
285                     choices.add("false");
286                 }
287 
288                 return choices.iterator();
289             }
290         };
291         mandatoryCondition.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
292 
293             private static final long serialVersionUID = -1107858522700306810L;
294 
295             @Override
296             protected void onUpdate(final AjaxRequestTarget target) {
297             }
298         });
299         add(mandatoryCondition);
300 
301         add(Constants.getJEXLPopover(this, TooltipConfig.Placement.right));
302 
303         add(new AjaxCheckBoxPanel(
304                 "multivalue", getString("multivalue"), new PropertyModel<>(schemaTO, "multivalue")));
305 
306         add(new AjaxCheckBoxPanel(
307                 "readonly", getString("readonly"), new PropertyModel<>(schemaTO, "readonly")));
308 
309         add(new AjaxCheckBoxPanel("uniqueConstraint",
310                 getString("uniqueConstraint"), new PropertyModel<>(schemaTO, "uniqueConstraint")).
311                 setEnabled(isCreate));
312     }
313 
314     private void showHide(final PlainSchemaTO schema, final AjaxDropDownChoicePanel<AttrSchemaType> type,
315             final WebMarkupContainer conversionParams, final AjaxTextFieldPanel conversionPattern,
316             final WebMarkupContainer enumParams, final AjaxTextFieldPanel enumerationValuesPanel,
317             final MultiFieldPanel<String> enumerationValues, final MultiFieldPanel<String> enumerationKeys,
318             final WebMarkupContainer encryptedParams,
319             final AjaxTextFieldPanel secretKey, final AjaxDropDownChoicePanel<CipherAlgorithm> cipherAlgorithm,
320             final WebMarkupContainer binaryParams, final AjaxTextFieldPanel mimeType) {
321 
322         int typeOrdinal = -1;
323         try {
324             typeOrdinal = Integer.parseInt(type.getField().getValue());
325         } catch (NumberFormatException e) {
326             LOG.error("Invalid value found: {}", type.getField().getValue(), e);
327         }
328         if (AttrSchemaType.Long.ordinal() == typeOrdinal
329                 || AttrSchemaType.Double.ordinal() == typeOrdinal
330                 || AttrSchemaType.Date.ordinal() == typeOrdinal) {
331 
332             conversionParams.setVisible(true);
333 
334             enumParams.setVisible(false);
335             if (enumerationValuesPanel.isRequired()) {
336                 enumerationValuesPanel.removeRequiredLabel();
337             }
338             enumerationValues.setModelObject(PropertyList.getEnumValuesAsList(null));
339             enumerationKeys.setModelObject(PropertyList.getEnumValuesAsList(null));
340 
341             encryptedParams.setVisible(false);
342             if (secretKey.isRequired()) {
343                 secretKey.removeRequiredLabel();
344             }
345             secretKey.setModelObject(null);
346             if (cipherAlgorithm.isRequired()) {
347                 cipherAlgorithm.removeRequiredLabel();
348             }
349             cipherAlgorithm.setModelObject(null);
350 
351             binaryParams.setVisible(false);
352             mimeType.setModelObject(null);
353             mimeType.setChoices(null);
354         } else if (AttrSchemaType.Enum.ordinal() == typeOrdinal) {
355             conversionParams.setVisible(false);
356             conversionPattern.setModelObject(null);
357 
358             enumParams.setVisible(true);
359             if (!enumerationValuesPanel.isRequired()) {
360                 enumerationValuesPanel.addRequiredLabel();
361             }
362             enumerationValues.setModelObject(PropertyList.getEnumValuesAsList(schema.getEnumerationValues()));
363             enumerationKeys.setModelObject(PropertyList.getEnumValuesAsList(schema.getEnumerationKeys()));
364 
365             encryptedParams.setVisible(false);
366             if (secretKey.isRequired()) {
367                 secretKey.removeRequiredLabel();
368             }
369             secretKey.setModelObject(null);
370             if (cipherAlgorithm.isRequired()) {
371                 cipherAlgorithm.removeRequiredLabel();
372             }
373             cipherAlgorithm.setModelObject(null);
374 
375             binaryParams.setVisible(false);
376             mimeType.setModelObject(null);
377             mimeType.setChoices(null);
378         } else if (AttrSchemaType.Encrypted.ordinal() == typeOrdinal) {
379             conversionParams.setVisible(false);
380 
381             enumParams.setVisible(false);
382             if (enumerationValuesPanel.isRequired()) {
383                 enumerationValuesPanel.removeRequiredLabel();
384             }
385             enumerationValues.setModelObject(PropertyList.getEnumValuesAsList(null));
386             enumerationKeys.setModelObject(PropertyList.getEnumValuesAsList(null));
387 
388             encryptedParams.setVisible(true);
389             if (!secretKey.isRequired()) {
390                 secretKey.addRequiredLabel();
391             }
392             if (cipherAlgorithm.isRequired()) {
393                 cipherAlgorithm.addRequiredLabel();
394             }
395 
396             binaryParams.setVisible(false);
397             mimeType.setModelObject(null);
398             mimeType.setChoices(null);
399         } else if (AttrSchemaType.Binary.ordinal() == typeOrdinal) {
400             conversionParams.setVisible(false);
401             conversionPattern.setModelObject(null);
402 
403             enumParams.setVisible(false);
404             if (enumerationValuesPanel.isRequired()) {
405                 enumerationValuesPanel.removeRequiredLabel();
406             }
407             enumerationValues.setModelObject(PropertyList.getEnumValuesAsList(null));
408             enumerationKeys.setModelObject(PropertyList.getEnumValuesAsList(null));
409 
410             encryptedParams.setVisible(false);
411             if (secretKey.isRequired()) {
412                 secretKey.removeRequiredLabel();
413             }
414             secretKey.setModelObject(null);
415             if (cipherAlgorithm.isRequired()) {
416                 cipherAlgorithm.removeRequiredLabel();
417             }
418             cipherAlgorithm.setModelObject(null);
419 
420             binaryParams.setVisible(true);
421             mimeType.setChoices(mimeTypesLoader.getMimeTypes());
422 
423             schema.setValidator("BinaryValidator");
424         } else {
425             conversionParams.setVisible(false);
426             conversionPattern.setModelObject(null);
427 
428             enumParams.setVisible(false);
429             if (enumerationValuesPanel.isRequired()) {
430                 enumerationValuesPanel.removeRequiredLabel();
431             }
432             enumerationValues.setModelObject(PropertyList.getEnumValuesAsList(null));
433             enumerationKeys.setModelObject(PropertyList.getEnumValuesAsList(null));
434 
435             encryptedParams.setVisible(false);
436             if (secretKey.isRequired()) {
437                 secretKey.removeRequiredLabel();
438             }
439             secretKey.setModelObject(null);
440             if (cipherAlgorithm.isRequired()) {
441                 cipherAlgorithm.removeRequiredLabel();
442             }
443             cipherAlgorithm.setModelObject(null);
444 
445             binaryParams.setVisible(false);
446             mimeType.setModelObject(null);
447             mimeType.setChoices(null);
448         }
449 
450         if (type.isEnabled() && AttrSchemaType.Binary.ordinal() != typeOrdinal) {
451             schema.setValidator(null);
452         }
453     }
454 }