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.enduser.panels.any;
20  
21  import java.util.List;
22  import java.util.stream.Collectors;
23  import org.apache.commons.collections4.ListUtils;
24  import org.apache.commons.lang3.StringUtils;
25  import org.apache.syncope.client.enduser.rest.GroupRestClient;
26  import org.apache.syncope.client.ui.commons.ajax.markup.html.LabelInfo;
27  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
28  import org.apache.syncope.client.ui.commons.wizards.any.AbstractGroupsModel;
29  import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper;
30  import org.apache.syncope.client.ui.commons.wizards.any.UserWrapper;
31  import org.apache.syncope.common.lib.to.AnyTO;
32  import org.apache.syncope.common.lib.to.GroupTO;
33  import org.apache.syncope.common.lib.to.GroupableRelatableTO;
34  import org.apache.syncope.common.lib.to.MembershipTO;
35  import org.apache.syncope.common.lib.to.UserTO;
36  import org.apache.wicket.ajax.AjaxRequestTarget;
37  import org.apache.wicket.event.Broadcast;
38  import org.apache.wicket.markup.html.WebMarkupContainer;
39  import org.apache.wicket.markup.html.basic.Label;
40  import org.apache.wicket.markup.html.form.IChoiceRenderer;
41  import org.apache.wicket.markup.html.panel.Panel;
42  import org.apache.wicket.model.IModel;
43  import org.apache.wicket.model.util.ListModel;
44  import org.apache.wicket.spring.injection.annot.SpringBean;
45  import org.danekja.java.util.function.serializable.SerializableFunction;
46  
47  public class Groups extends Panel {
48  
49      private static final long serialVersionUID = 552437609667518888L;
50  
51      protected static final int MAX_GROUP_LIST_CARDINALITY = 30;
52  
53      @SpringBean
54      protected GroupRestClient groupRestClient;
55  
56      protected final EnduserGroupsModel groupsModel;
57  
58      protected final AnyTO anyTO;
59  
60      protected WebMarkupContainer dyngroupsContainer;
61  
62      protected WebMarkupContainer dynrealmsContainer;
63  
64      protected WebMarkupContainer groupsContainer;
65  
66      public <T extends AnyTO> Groups(final String id, final AnyWrapper<T> modelObject) {
67          super(id);
68          this.anyTO = modelObject.getInnerObject();
69  
70          setOutputMarkupId(true);
71  
72          groupsContainer = new WebMarkupContainer("groupsContainer");
73          groupsContainer.setOutputMarkupId(true);
74          groupsContainer.setOutputMarkupPlaceholderTag(true);
75          add(groupsContainer);
76  
77          // ------------------
78          // insert changed label if needed
79          // ------------------
80          if (modelObject instanceof UserWrapper
81                  && UserWrapper.class.cast(modelObject).getPreviousUserTO() != null
82                  && !ListUtils.isEqualList(
83                          UserWrapper.class.cast(modelObject).getInnerObject().getMemberships(),
84                          UserWrapper.class.cast(modelObject).getPreviousUserTO().getMemberships())) {
85              groupsContainer.add(new LabelInfo("changed", StringUtils.EMPTY));
86          } else {
87              groupsContainer.add(new Label("changed", StringUtils.EMPTY));
88          }
89          // ------------------
90  
91          this.groupsModel = new EnduserGroupsModel();
92  
93          setOutputMarkupId(true);
94  
95          addDynamicGroupsContainer();
96          addGroupsPanel();
97          addDynamicRealmsContainer();
98      }
99  
100     protected SerializableFunction<AjaxRequestTarget, Boolean> getEventFunction() {
101         return target -> {
102             send(Groups.this.getPage(), Broadcast.BREADTH,
103                     new AjaxPalettePanel.UpdateActionEvent((UserTO) anyTO, target));
104             return true;
105         };
106     }
107 
108     protected void addGroupsPanel() {
109         if (anyTO instanceof GroupTO) {
110             groupsContainer.add(new Label("groups").setVisible(false));
111             groupsContainer.setVisible(false);
112         } else {
113             AjaxPalettePanel.Builder<MembershipTO> builder = new AjaxPalettePanel.Builder<MembershipTO>().
114                     setRenderer(new IChoiceRenderer<>() {
115 
116                         private static final long serialVersionUID = -3086661086073628855L;
117 
118                         @Override
119                         public Object getDisplayValue(final MembershipTO object) {
120                             return object.getGroupName();
121                         }
122 
123                         @Override
124                         public String getIdValue(final MembershipTO object, final int index) {
125                             return object.getGroupName();
126                         }
127 
128                         @Override
129                         public MembershipTO getObject(
130                                 final String id, final IModel<? extends List<? extends MembershipTO>> choices) {
131 
132                             return choices.getObject().stream().
133                                     filter(object -> id.equalsIgnoreCase(object.getGroupName())).findAny().orElse(null);
134                         }
135                     }).event(getEventFunction());
136 
137             groupsContainer.add(builder.setAllowOrder(true).withFilter().build("groups",
138                     new ListModel<>() {
139 
140                 private static final long serialVersionUID = -2583290457773357445L;
141 
142                 @Override
143                 public List<MembershipTO> getObject() {
144                     return Groups.this.groupsModel.getMemberships();
145                 }
146 
147             }, new AjaxPalettePanel.Builder.Query<>() {
148 
149                 private static final long serialVersionUID = -7223078772249308813L;
150 
151                 @Override
152                 public List<MembershipTO> execute(final String filter) {
153                     return (StringUtils.isEmpty(filter) || "*".equals(filter)
154                             ? groupsModel.getObject()
155                             : groupRestClient.searchAssignableGroups(
156                                     anyTO.getRealm(),
157                                     filter,
158                                     1, MAX_GROUP_LIST_CARDINALITY)).stream()
159                             .map(input -> new MembershipTO.Builder(input.getKey())
160                             .groupName(input.getName()).build()).collect(Collectors.toList());
161                 }
162             }).hideLabel().setOutputMarkupId(true));
163             // ---------------------------------
164         }
165     }
166 
167     protected void addDynamicRealmsContainer() {
168     }
169 
170     protected void addDynamicGroupsContainer() {
171     }
172 
173     protected class EnduserGroupsModel extends AbstractGroupsModel {
174 
175         private static final long serialVersionUID = -4541954630939063927L;
176 
177         @Override
178         public List<GroupTO> getObject() {
179             reload();
180             return groups;
181         }
182 
183         /**
184          * Retrieve the first MAX_GROUP_LIST_CARDINALITY assignable.
185          */
186         @Override
187         protected void reloadObject() {
188             groups = groupRestClient.searchAssignableGroups(
189                     realm,
190                     null,
191                     1,
192                     MAX_GROUP_LIST_CARDINALITY);
193         }
194 
195         @Override
196         public List<MembershipTO> getMemberships() {
197             reload();
198             return memberships;
199         }
200 
201         /**
202          * Retrieve group memberships.
203          */
204         @Override
205         protected void reloadMemberships() {
206             memberships = GroupableRelatableTO.class.cast(anyTO).getMemberships();
207         }
208 
209         @Override
210         public List<String> getDynMemberships() {
211             return List.of();
212         }
213 
214         /**
215          * Retrieve dyn group memberships.
216          */
217         @Override
218         protected void reloadDynMemberships() {
219             // DO NOTHING
220         }
221 
222         /**
223          * Reload data if the realm changes (see SYNCOPE-1135).
224          */
225         @Override
226         protected void reload() {
227             boolean reload = Groups.this.anyTO.getRealm() != null
228                     && !Groups.this.anyTO.getRealm().equalsIgnoreCase(realm);
229             realm = Groups.this.anyTO.getRealm();
230 
231             if (reload) {
232                 reloadObject();
233                 reloadMemberships();
234             }
235         }
236     }
237 }