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.status;
20  
21  import java.util.Iterator;
22  import java.util.List;
23  import java.util.stream.Collectors;
24  import org.apache.commons.lang3.StringUtils;
25  import org.apache.syncope.client.console.SyncopeConsoleSession;
26  import org.apache.syncope.client.console.SyncopeWebApplication;
27  import org.apache.syncope.client.console.commons.RealmsUtils;
28  import org.apache.syncope.client.console.pages.BasePage;
29  import org.apache.syncope.client.console.panels.MultilevelPanel;
30  import org.apache.syncope.client.console.rest.ImplementationRestClient;
31  import org.apache.syncope.client.console.rest.RealmRestClient;
32  import org.apache.syncope.client.console.rest.ReconciliationRestClient;
33  import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel;
34  import org.apache.syncope.client.ui.commons.Constants;
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.common.lib.SyncopeConstants;
39  import org.apache.syncope.common.lib.to.ImplementationTO;
40  import org.apache.syncope.common.lib.to.ProvisioningTaskTO;
41  import org.apache.syncope.common.lib.to.PullTaskTO;
42  import org.apache.syncope.common.lib.to.PushTaskTO;
43  import org.apache.syncope.common.lib.to.RealmTO;
44  import org.apache.syncope.common.lib.types.IdMImplementationType;
45  import org.apache.syncope.common.lib.types.MatchingRule;
46  import org.apache.syncope.common.lib.types.UnmatchingRule;
47  import org.apache.syncope.common.rest.api.beans.ReconQuery;
48  import org.apache.wicket.PageReference;
49  import org.apache.wicket.ajax.AjaxRequestTarget;
50  import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
51  import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
52  import org.apache.wicket.markup.html.basic.Label;
53  import org.apache.wicket.markup.html.form.Form;
54  import org.apache.wicket.model.CompoundPropertyModel;
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  import org.apache.wicket.spring.injection.annot.SpringBean;
60  import org.slf4j.Logger;
61  import org.slf4j.LoggerFactory;
62  
63  public class ReconTaskPanel extends MultilevelPanel.SecondLevel {
64  
65      private static final long serialVersionUID = 5870444905957760434L;
66  
67      protected static final Logger LOG = LoggerFactory.getLogger(ReconTaskPanel.class);
68  
69      @SpringBean
70      protected ImplementationRestClient implementationRestClient;
71  
72      @SpringBean
73      protected RealmRestClient realmRestClient;
74  
75      @SpringBean
76      protected ReconciliationRestClient reconciliationRestClient;
77  
78      protected final IModel<List<String>> pullActions = new LoadableDetachableModel<>() {
79  
80          private static final long serialVersionUID = 5275935387613157437L;
81  
82          @Override
83          protected List<String> load() {
84              return implementationRestClient.list(IdMImplementationType.PULL_ACTIONS).stream().
85                      map(ImplementationTO::getKey).sorted().collect(Collectors.toList());
86          }
87      };
88  
89      protected final IModel<List<String>> pushActions = new LoadableDetachableModel<>() {
90  
91          private static final long serialVersionUID = 5275935387613157437L;
92  
93          @Override
94          protected List<String> load() {
95              return implementationRestClient.list(IdMImplementationType.PUSH_ACTIONS).stream().
96                      map(ImplementationTO::getKey).sorted().collect(Collectors.toList());
97          }
98      };
99  
100     public ReconTaskPanel(
101             final String resource,
102             final ProvisioningTaskTO taskTO,
103             final String anyType,
104             final String anyKey,
105             final boolean isOnSyncope,
106             final MultilevelPanel multiLevelPanelRef,
107             final PageReference pageRef) {
108 
109         this(resource, taskTO, anyType, anyKey, null, isOnSyncope, multiLevelPanelRef, pageRef);
110     }
111 
112     public ReconTaskPanel(
113             final String resource,
114             final ProvisioningTaskTO taskTO,
115             final String anyType,
116             final String anyKey,
117             final String fiql,
118             final boolean isOnSyncope,
119             final MultilevelPanel multiLevelPanelRef,
120             final PageReference pageRef) {
121 
122         Form<ProvisioningTaskTO> form = new Form<>("form", new CompoundPropertyModel<>(taskTO));
123         add(form);
124 
125         if (taskTO instanceof PushTaskTO) {
126             form.add(new Label("realm", ""));
127             form.add(new Label("remediation", ""));
128         } else {
129             boolean fullRealmsTree = SyncopeWebApplication.get().fullRealmsTree(realmRestClient);
130             AutoCompleteSettings settings = new AutoCompleteSettings();
131             settings.setShowCompleteListOnFocusGain(fullRealmsTree);
132             settings.setShowListOnEmptyInput(fullRealmsTree);
133 
134             AjaxSearchFieldPanel realm = new AjaxSearchFieldPanel(
135                     "realm", "destinationRealm", new PropertyModel<>(taskTO, "destinationRealm"), settings) {
136 
137                 private static final long serialVersionUID = -6390474600233486704L;
138 
139                 @Override
140                 protected Iterator<String> getChoices(final String input) {
141                     return (RealmsUtils.checkInput(input)
142                             ? (realmRestClient.search(fullRealmsTree
143                                     ? RealmsUtils.buildRootQuery()
144                                     : RealmsUtils.buildKeywordQuery(input)).getResult())
145                             : List.<RealmTO>of()).stream().
146                             map(RealmTO::getFullPath).collect(Collectors.toList()).iterator();
147                 }
148             };
149 
150             realm.addRequiredLabel();
151             realm.setOutputMarkupId(true);
152             // add a default destination realm if missing in the task
153             if (StringUtils.isBlank(PullTaskTO.class.cast(taskTO).getDestinationRealm())) {
154                 realm.getField().setModelObject(SyncopeConstants.ROOT_REALM);
155             }
156             if (isOnSyncope) {
157                 realm.setEnabled(false);
158             }
159             form.add(realm);
160 
161             form.add(new AjaxCheckBoxPanel(
162                     "remediation", "remediation", new PropertyModel<>(taskTO, "remediation"), false));
163         }
164 
165         AjaxPalettePanel<String> actions = new AjaxPalettePanel.Builder<String>().
166                 setAllowMoveAll(true).setAllowOrder(true).
167                 build("actions",
168                         new PropertyModel<>(taskTO, "actions"),
169                         new ListModel<>(taskTO instanceof PushTaskTO
170                                 ? pushActions.getObject() : pullActions.getObject()));
171         actions.setOutputMarkupId(true);
172         form.add(actions);
173 
174         AjaxDropDownChoicePanel<MatchingRule> matchingRule = new AjaxDropDownChoicePanel<>(
175                 "matchingRule", "matchingRule", new PropertyModel<>(taskTO, "matchingRule"), false);
176         matchingRule.setChoices(List.of(MatchingRule.values()));
177         form.add(matchingRule);
178 
179         AjaxDropDownChoicePanel<UnmatchingRule> unmatchingRule = new AjaxDropDownChoicePanel<>(
180                 "unmatchingRule", "unmatchingRule", new PropertyModel<>(taskTO, "unmatchingRule"),
181                 false);
182         unmatchingRule.setChoices(List.of(UnmatchingRule.values()));
183         form.add(unmatchingRule);
184 
185         taskTO.setPerformCreate(true);
186         AjaxCheckBoxPanel performCreate = new AjaxCheckBoxPanel(
187                 "performCreate", "performCreate", new PropertyModel<>(taskTO, "performCreate"), false);
188         form.add(performCreate);
189 
190         taskTO.setPerformUpdate(true);
191         AjaxCheckBoxPanel performUpdate = new AjaxCheckBoxPanel(
192                 "performUpdate", "performUpdate", new PropertyModel<>(taskTO, "performUpdate"), false);
193         form.add(performUpdate);
194 
195         taskTO.setPerformDelete(true);
196         AjaxCheckBoxPanel performDelete = new AjaxCheckBoxPanel(
197                 "performDelete", "performDelete", new PropertyModel<>(taskTO, "performDelete"), false);
198         form.add(performDelete);
199 
200         taskTO.setSyncStatus(true);
201         AjaxCheckBoxPanel syncStatus = new AjaxCheckBoxPanel(
202                 "syncStatus", "syncStatus", new PropertyModel<>(taskTO, "syncStatus"), false);
203         form.add(syncStatus);
204 
205         form.add(new AjaxSubmitLink("reconcile") {
206 
207             private static final long serialVersionUID = -817438685948164787L;
208 
209             @Override
210             protected void onSubmit(final AjaxRequestTarget target) {
211                 ReconQuery reconQuery = new ReconQuery.Builder(anyType, resource).anyKey(anyKey).fiql(fiql).build();
212                 try {
213                     if (taskTO instanceof PushTaskTO) {
214                         reconciliationRestClient.push(reconQuery, (PushTaskTO) form.getModelObject());
215                     } else {
216                         reconciliationRestClient.pull(reconQuery, (PullTaskTO) form.getModelObject());
217                     }
218 
219                     SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
220                 } catch (Exception e) {
221                     LOG.error("While attempting reconciliation using query {} on {}",
222                             reconQuery, form.getModelObject(), e);
223                     SyncopeConsoleSession.get().onException(e);
224                 }
225                 multiLevelPanelRef.prev(target);
226                 ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
227             }
228         });
229     }
230 }