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.ui.commons.panels;
20  
21  import java.text.ParseException;
22  import java.util.ArrayList;
23  import java.util.Date;
24  import java.util.List;
25  import java.util.Optional;
26  import java.util.stream.Collectors;
27  import org.apache.commons.lang3.BooleanUtils;
28  import org.apache.commons.lang3.StringUtils;
29  import org.apache.commons.lang3.math.NumberUtils;
30  import org.apache.commons.lang3.time.FastDateFormat;
31  import org.apache.syncope.client.ui.commons.MapChoiceRenderer;
32  import org.apache.syncope.client.ui.commons.markup.html.form.AbstractFieldPanel;
33  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
34  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateTimeFieldPanel;
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.AjaxPasswordFieldPanel;
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.common.lib.form.FormProperty;
41  import org.apache.syncope.common.lib.form.FormPropertyValue;
42  import org.apache.syncope.common.lib.form.SyncopeForm;
43  import org.apache.wicket.markup.html.list.ListItem;
44  import org.apache.wicket.markup.html.list.ListView;
45  import org.apache.wicket.markup.html.panel.Panel;
46  import org.apache.wicket.model.IModel;
47  import org.apache.wicket.model.PropertyModel;
48  import org.apache.wicket.model.util.ListModel;
49  import org.apache.wicket.validation.validator.PatternValidator;
50  import org.slf4j.Logger;
51  import org.slf4j.LoggerFactory;
52  
53  public class SyncopeFormPanel<F extends SyncopeForm> extends Panel {
54  
55      private static final long serialVersionUID = -8847854414429745216L;
56  
57      protected static final Logger LOG = LoggerFactory.getLogger(SyncopeFormPanel.class);
58  
59      public SyncopeFormPanel(final String id, final F form) {
60          super(id);
61  
62          ListModel<FormProperty> model = new ListModel<>(new ArrayList<>());
63          model.getObject().addAll(form.getProperties());
64  
65          ListView<FormProperty> propView = new ListView<>("propView", model) {
66  
67              private static final long serialVersionUID = 9101744072914090143L;
68  
69              @Override
70              protected void populateItem(final ListItem<FormProperty> item) {
71                  FormProperty prop = item.getModelObject();
72  
73                  String label = StringUtils.isBlank(prop.getName()) ? prop.getId() : prop.getName();
74  
75                  AbstractFieldPanel<?> field;
76                  switch (prop.getType()) {
77                      case Boolean:
78                          field = new AjaxCheckBoxPanel("value", label, new PropertyModel<Boolean>(prop, "value") {
79  
80                              private static final long serialVersionUID = -3743432456095828573L;
81  
82                              @Override
83                              public Boolean getObject() {
84                                  return BooleanUtils.toBoolean(prop.getValue());
85                              }
86  
87                              @Override
88                              public void setObject(final Boolean object) {
89                                  prop.setValue(BooleanUtils.toStringTrueFalse(object));
90                              }
91                          }, false);
92                          break;
93  
94                      case Date:
95                          FastDateFormat formatter = FastDateFormat.getInstance(prop.getDatePattern());
96                          field = new AjaxDateTimeFieldPanel("value", label, new PropertyModel<>(prop, "value") {
97  
98                              private static final long serialVersionUID = -3743432456095828573L;
99  
100                             @Override
101                             public Date getObject() {
102                                 try {
103                                     return StringUtils.isBlank(prop.getValue())
104                                             ? null
105                                             : formatter.parse(prop.getValue());
106                                 } catch (ParseException e) {
107                                     LOG.error("Unparsable date: {}", prop.getValue(), e);
108                                     return null;
109                                 }
110                             }
111 
112                             @Override
113                             public void setObject(final Date object) {
114                                 prop.setValue(formatter.format(object));
115                             }
116                         }, formatter);
117                         break;
118 
119                     case Enum:
120                         field = new AjaxDropDownChoicePanel<>(
121                                 "value", label, new PropertyModel<String>(prop, "value"), false).
122                                 setChoiceRenderer(new MapChoiceRenderer(prop.getEnumValues().stream().
123                                         collect(Collectors.toMap(
124                                                 FormPropertyValue::getKey,
125                                                 FormPropertyValue::getValue)))).
126                                 setChoices(prop.getEnumValues().stream().
127                                         map(FormPropertyValue::getKey).collect(Collectors.toList()));
128                         break;
129 
130                     case Dropdown:
131                         if (prop.isDropdownFreeForm()) {
132                             field = new AjaxTextFieldPanel("value", label, new PropertyModel<>(prop, "value"), false);
133                             ((AjaxTextFieldPanel) field).setChoices(prop.getDropdownValues().stream().
134                                     map(FormPropertyValue::getKey).collect(Collectors.toList()));
135                         } else if (prop.isDropdownSingleSelection()) {
136                             field = new AjaxDropDownChoicePanel<>(
137                                     "value", label, new PropertyModel<String>(prop, "value"), false).
138                                     setChoiceRenderer(new MapChoiceRenderer(prop.getDropdownValues().stream().
139                                             collect(Collectors.toMap(
140                                                     FormPropertyValue::getKey,
141                                                     FormPropertyValue::getValue)))).
142                                     setChoices(prop.getDropdownValues().stream().
143                                             map(FormPropertyValue::getKey).collect(Collectors.toList()));
144                         } else {
145                             field = new AjaxPalettePanel.Builder<String>().setName(label).
146                                     setRenderer(new MapChoiceRenderer(prop.getDropdownValues().stream().
147                                             collect(Collectors.toMap(
148                                                     FormPropertyValue::getKey,
149                                                     FormPropertyValue::getValue)))).build(
150                                     "value",
151                                     new IModel<List<String>>() {
152 
153                                 private static final long serialVersionUID = 1015030402166681242L;
154 
155                                 @Override
156                                 public List<String> getObject() {
157                                     return Optional.ofNullable(prop.getValue()).
158                                             map(v -> List.of(v.split(";"))).
159                                             orElse(null);
160                                 }
161 
162                                 @Override
163                                 public void setObject(final List<String> object) {
164                                     prop.setValue(Optional.ofNullable(object).
165                                             map(v -> v.stream().collect(Collectors.joining(";"))).
166                                             orElse(null));
167                                 }
168                             }, new ListModel<>(prop.getDropdownValues().stream().
169                                             map(FormPropertyValue::getKey).collect(Collectors.toList())));
170                         }
171                         break;
172 
173                     case Long:
174                         field = new AjaxSpinnerFieldPanel.Builder<Long>().build(
175                                 "value",
176                                 label,
177                                 Long.class,
178                                 new PropertyModel<>(prop, "value") {
179 
180                             private static final long serialVersionUID = -7688359318035249200L;
181 
182                             @Override
183                             public Long getObject() {
184                                 return StringUtils.isBlank(prop.getValue())
185                                         ? null
186                                         : NumberUtils.toLong(prop.getValue());
187                             }
188 
189                             @Override
190                             public void setObject(final Long object) {
191                                 prop.setValue(String.valueOf(object));
192                             }
193                         });
194                         break;
195 
196                     case Password:
197                         field = new AjaxPasswordFieldPanel("value", label, new PropertyModel<>(prop, "value"), false).
198                                 setResetPassword(false);
199                         break;
200 
201                     case String:
202                     default:
203                         field = new AjaxTextFieldPanel("value", label, new PropertyModel<>(prop, "value"), false);
204                         Optional.ofNullable(prop.getStringRegEx()).
205                                 ifPresent(re -> ((AjaxTextFieldPanel) field).addValidator(new PatternValidator(re)));
206                         break;
207                 }
208 
209                 field.setReadOnly(!prop.isWritable());
210                 if (prop.isRequired()) {
211                     field.addRequiredLabel();
212                 }
213 
214                 item.add(field);
215             }
216         };
217         add(propView.setReuseItems(true));
218     }
219 }