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 java.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Locale;
25  import java.util.Objects;
26  import java.util.stream.Collectors;
27  import org.apache.commons.lang3.LocaleUtils;
28  import org.apache.commons.lang3.StringUtils;
29  import org.apache.commons.lang3.tuple.MutablePair;
30  import org.apache.syncope.client.console.SyncopeConsoleSession;
31  import org.apache.syncope.client.console.SyncopeWebApplication;
32  import org.apache.syncope.client.console.rest.SchemaRestClient;
33  import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
34  import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
35  import org.apache.syncope.client.console.wizards.BaseAjaxWizardBuilder;
36  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
37  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
38  import org.apache.syncope.common.lib.to.DerSchemaTO;
39  import org.apache.syncope.common.lib.to.PlainSchemaTO;
40  import org.apache.syncope.common.lib.to.SchemaTO;
41  import org.apache.syncope.common.lib.to.VirSchemaTO;
42  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
43  import org.apache.syncope.common.lib.types.SchemaType;
44  import org.apache.wicket.PageReference;
45  import org.apache.wicket.ajax.AjaxRequestTarget;
46  import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
47  import org.apache.wicket.extensions.wizard.WizardModel;
48  import org.apache.wicket.extensions.wizard.WizardStep;
49  import org.apache.wicket.markup.html.list.ListItem;
50  import org.apache.wicket.markup.html.list.ListView;
51  import org.apache.wicket.markup.html.panel.Panel;
52  import org.apache.wicket.model.IModel;
53  import org.apache.wicket.model.Model;
54  import org.apache.wicket.model.ResourceModel;
55  import org.apache.wicket.model.util.ListModel;
56  import org.apache.wicket.request.cycle.RequestCycle;
57  import org.apache.wicket.validation.ValidationError;
58  
59  public class SchemaTypeWizardBuilder extends BaseAjaxWizardBuilder<SchemaTO> {
60  
61      private static final long serialVersionUID = -3893521796674873644L;
62  
63      protected final SchemaType schemaType;
64  
65      protected final SchemaRestClient schemaRestClient;
66  
67      protected final ListModel<MutablePair<Locale, String>> translations = new ListModel<>(new ArrayList<>());
68  
69      public SchemaTypeWizardBuilder(
70              final SchemaTO schemaTO,
71              final SchemaRestClient schemaRestClient,
72              final PageReference pageRef) {
73  
74          super(schemaTO, pageRef);
75  
76          this.schemaType = SchemaType.fromToClass(schemaTO.getClass());
77          this.schemaRestClient = schemaRestClient;
78      }
79  
80      @Override
81      protected Serializable onApplyInternal(final SchemaTO modelObject) {
82          modelObject.getLabels().clear();
83          modelObject.getLabels().putAll(translations.getObject().stream().
84                  filter(Objects::nonNull).
85                  filter(translation -> translation.getKey() != null).
86                  filter(translation -> translation.getValue() != null).
87                  collect(Collectors.toMap(MutablePair::getKey, MutablePair::getValue)));
88  
89          if (getOriginalItem() == null || StringUtils.isBlank(getOriginalItem().getKey())) {
90              schemaRestClient.create(schemaType, modelObject);
91          } else {
92              schemaRestClient.update(schemaType, modelObject);
93          }
94  
95          return null;
96      }
97  
98      @Override
99      protected WizardModel buildModelSteps(final SchemaTO modelObject, final WizardModel wizardModel) {
100         wizardModel.add(new Details(modelObject));
101         wizardModel.add(new Labels(modelObject));
102         return wizardModel;
103     }
104 
105     public class Details extends WizardStep {
106 
107         private static final long serialVersionUID = 382498949020534783L;
108 
109         public Details(final SchemaTO modelObject) {
110             AjaxDropDownChoicePanel<SchemaType> kind =
111                     new AjaxDropDownChoicePanel<>("kind", getString("kind"), new Model<>());
112             kind.setChoices(List.of(SchemaType.values()));
113             kind.setOutputMarkupId(true);
114             kind.setModelObject(schemaType);
115             kind.setEnabled(false);
116             add(kind);
117 
118             Panel detailsPanel;
119             switch (schemaType) {
120                 case DERIVED:
121                     detailsPanel = new DerSchemaDetails("details", (DerSchemaTO) modelObject);
122                     break;
123 
124                 case VIRTUAL:
125                     detailsPanel = SyncopeWebApplication.get().getVirSchemaDetailsPanelProvider().
126                             get("details", (VirSchemaTO) modelObject);
127                     break;
128 
129                 case PLAIN:
130                 default:
131                     detailsPanel = new PlainSchemaDetails("details", (PlainSchemaTO) modelObject);
132             }
133             add(detailsPanel.setOutputMarkupId(true));
134         }
135     }
136 
137     public class Labels extends WizardStep {
138 
139         private static final long serialVersionUID = -3130973642912822270L;
140 
141         public Labels(final SchemaTO modelObject) {
142             setTitleModel(new ResourceModel("translations"));
143             setOutputMarkupId(true);
144 
145             translations.getObject().clear();
146             modelObject.getLabels().forEach(
147                     (locale, display) -> translations.getObject().add(MutablePair.of(locale, display)));
148 
149             ListView<MutablePair<Locale, String>> labels = new ListView<>("labels", translations) {
150 
151                 private static final long serialVersionUID = -8746795666847966508L;
152 
153                 @Override
154                 protected void populateItem(final ListItem<MutablePair<Locale, String>> item) {
155                     MutablePair<Locale, String> entry = item.getModelObject();
156 
157                     AjaxTextFieldPanel locale = new AjaxTextFieldPanel("locale", "locale", new Model<>(), true);
158                     locale.getField().setModel(new IModel<>() {
159 
160                         private static final long serialVersionUID = 1500045101360533133L;
161 
162                         @Override
163                         public String getObject() {
164                             return entry.getLeft() == null ? null : entry.getLeft().toString();
165                         }
166 
167                         @Override
168                         public void setObject(final String object) {
169                             entry.setLeft(LocaleUtils.toLocale(object));
170                         }
171                     });
172                     locale.setRequired(true).hideLabel();
173                     locale.setChoices(SyncopeConsoleSession.get().getSupportedLocales().stream().
174                             map(Objects::toString).collect(Collectors.toList()));
175                     locale.addValidator(validatable -> {
176                         try {
177                             LocaleUtils.toLocale(validatable.getValue());
178                         } catch (Exception e) {
179                             LOG.error("Invalid Locale: {}", validatable.getValue(), e);
180                             validatable.error(new ValidationError("Invalid Locale: " + validatable.getValue()));
181 
182                             RequestCycle.get().find(AjaxRequestTarget.class).
183                                     ifPresent(target -> target.add(Labels.this));
184                         }
185                     });
186                     item.add(locale);
187 
188                     AjaxTextFieldPanel display = new AjaxTextFieldPanel("display", "display", new Model<>());
189                     display.getField().setModel(new IModel<>() {
190 
191                         private static final long serialVersionUID = 1500045101360533133L;
192 
193                         @Override
194                         public String getObject() {
195                             return entry.getRight();
196                         }
197 
198                         @Override
199                         public void setObject(final String object) {
200                             entry.setRight(object);
201                         }
202                     });
203                     display.setRequired(true).hideLabel();
204                     item.add(display);
205 
206                     ActionsPanel<Serializable> actions = new ActionsPanel<>("toRemove", null);
207                     actions.add(new ActionLink<>() {
208 
209                         private static final long serialVersionUID = -3722207913631435501L;
210 
211                         @Override
212                         public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
213                             translations.getObject().remove(item.getIndex());
214 
215                             item.getParent().removeAll();
216                             target.add(Labels.this);
217                         }
218                     }, ActionLink.ActionType.DELETE, IdRepoEntitlement.SCHEMA_UPDATE, true).hideLabel();
219                     item.add(actions);
220                 }
221             };
222             add(labels.setReuseItems(true));
223 
224             IndicatingAjaxButton addLabel = new IndicatingAjaxButton("addLabel") {
225 
226                 private static final long serialVersionUID = -4804368561204623354L;
227 
228                 @Override
229                 protected void onSubmit(final AjaxRequestTarget target) {
230                     translations.getObject().add(MutablePair.of(null, null));
231                     target.add(Labels.this);
232                 }
233             };
234             add(addLabel.setDefaultFormProcessing(false));
235         }
236     }
237 }