1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.console.panels;
20
21 import static org.apache.syncope.common.lib.types.AnyTypeKind.ANY_OBJECT;
22 import static org.apache.syncope.common.lib.types.AnyTypeKind.GROUP;
23 import static org.apache.syncope.common.lib.types.AnyTypeKind.USER;
24
25 import java.io.Serializable;
26 import java.util.ArrayList;
27 import java.util.List;
28 import org.apache.commons.lang3.StringUtils;
29 import org.apache.syncope.client.console.commons.RealmsUtils;
30 import org.apache.syncope.client.console.layout.AnyLayout;
31 import org.apache.syncope.client.console.layout.AnyLayoutUtils;
32 import org.apache.syncope.client.console.panels.search.AbstractSearchPanel;
33 import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel;
34 import org.apache.syncope.client.console.panels.search.GroupSearchPanel;
35 import org.apache.syncope.client.console.panels.search.SearchClause;
36 import org.apache.syncope.client.console.panels.search.SearchClausePanel;
37 import org.apache.syncope.client.console.panels.search.SearchUtils;
38 import org.apache.syncope.client.console.panels.search.UserSearchPanel;
39 import org.apache.syncope.client.console.rest.AnyObjectRestClient;
40 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
41 import org.apache.syncope.client.console.rest.GroupRestClient;
42 import org.apache.syncope.client.console.rest.UserRestClient;
43 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksTogglePanel;
44 import org.apache.syncope.client.lib.SyncopeClient;
45 import org.apache.syncope.client.ui.commons.Constants;
46 import org.apache.syncope.client.ui.commons.panels.LabelPanel;
47 import org.apache.syncope.client.ui.commons.panels.ModalPanel;
48 import org.apache.syncope.client.ui.commons.wicket.markup.html.bootstrap.tabs.Accordion;
49 import org.apache.syncope.common.lib.SyncopeConstants;
50 import org.apache.syncope.common.lib.to.AnyObjectTO;
51 import org.apache.syncope.common.lib.to.AnyTypeTO;
52 import org.apache.syncope.common.lib.to.GroupTO;
53 import org.apache.syncope.common.lib.to.RealmTO;
54 import org.apache.syncope.common.lib.to.UserTO;
55 import org.apache.syncope.common.lib.types.AnyEntitlement;
56 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
57 import org.apache.wicket.Component;
58 import org.apache.wicket.PageReference;
59 import org.apache.wicket.ajax.AjaxRequestTarget;
60 import org.apache.wicket.ajax.markup.html.AjaxLink;
61 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
62 import org.apache.wicket.event.Broadcast;
63 import org.apache.wicket.event.IEvent;
64 import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
65 import org.apache.wicket.extensions.markup.html.tabs.ITab;
66 import org.apache.wicket.markup.html.WebMarkupContainer;
67 import org.apache.wicket.markup.html.WebPage;
68 import org.apache.wicket.markup.html.panel.Panel;
69 import org.apache.wicket.model.Model;
70 import org.apache.wicket.model.ResourceModel;
71 import org.apache.wicket.model.util.ListModel;
72 import org.apache.wicket.spring.injection.annot.SpringBean;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75 import org.springframework.util.ClassUtils;
76
77 public class AnyPanel extends Panel implements ModalPanel {
78
79 private static final long serialVersionUID = -1100228004207271270L;
80
81 protected static final Logger LOG = LoggerFactory.getLogger(AnyPanel.class);
82
83 protected static final String DIRECTORY_PANEL_ID = "searchResult";
84
85 @FunctionalInterface
86 public interface DirectoryPanelSupplier extends Serializable {
87
88 Panel supply(
89 String id,
90 AnyTypeTO anyTypeTO,
91 RealmTO realmTO,
92 AnyLayout anyLayout,
93 PageReference pageRef);
94 }
95
96 public static class Builder<AP extends AnyPanel> {
97
98 private final AP instance;
99
100 public Builder(
101 final String panelClass,
102 final String id,
103 final AnyTypeTO anyTypeTO,
104 final RealmTO realmTO,
105 final AnyLayout anyLayout,
106 final boolean enableSearch,
107 final PageReference pageRef) {
108
109 try {
110 @SuppressWarnings("unchecked")
111 Class<AP> clazz = (Class<AP>) ClassUtils.forName(panelClass, ClassUtils.getDefaultClassLoader());
112 instance = clazz.getDeclaredConstructor(
113 String.class,
114 AnyTypeTO.class,
115 RealmTO.class,
116 AnyLayout.class,
117 boolean.class,
118 PageReference.class).
119 newInstance(id, anyTypeTO, realmTO, anyLayout, enableSearch, pageRef);
120 } catch (Exception e) {
121 throw new IllegalArgumentException("Could not instantiate " + panelClass, e);
122 }
123 }
124
125 public AP build() {
126 return build(instance.getDefaultDirectoryPanelSupplier());
127 }
128
129 public AP build(final DirectoryPanelSupplier directoryPanelSupplier) {
130 instance.directoryPanel =
131 instance.createDirectoryPanel(
132 instance.anyTypeTO,
133 instance.realmTO,
134 instance.anyLayout,
135 directoryPanelSupplier);
136 instance.add(instance.directoryPanel);
137 return instance;
138 }
139 }
140
141 @SpringBean
142 protected AnyTypeClassRestClient anyTypeClassRestClient;
143
144 @SpringBean
145 protected UserRestClient userRestClient;
146
147 @SpringBean
148 protected GroupRestClient groupRestClient;
149
150 @SpringBean
151 protected AnyObjectRestClient anyObjectRestClient;
152
153 protected final AnyTypeTO anyTypeTO;
154
155 protected final RealmTO realmTO;
156
157 protected final AnyLayout anyLayout;
158
159 protected final PageReference pageRef;
160
161 protected AbstractSearchPanel searchPanel;
162
163 protected Panel directoryPanel;
164
165 protected AnyPanel(
166 final String id,
167 final AnyTypeTO anyTypeTO,
168 final RealmTO realmTO,
169 final AnyLayout anyLayout,
170 final boolean enableSearch,
171 final PageReference pageRef) {
172
173 super(id);
174 this.anyTypeTO = anyTypeTO;
175 this.realmTO = realmTO;
176 this.anyLayout = anyLayout;
177 this.pageRef = pageRef;
178
179
180
181
182 Model<Integer> model = Model.of(-1);
183 Accordion accordion = new Accordion("accordionPanel",
184 List.of(new AbstractTab(new ResourceModel("search.result")) {
185
186 protected static final long serialVersionUID = 1037272333056449377L;
187
188 @Override
189 public WebMarkupContainer getPanel(final String panelId) {
190 searchPanel = getSearchPanel(panelId);
191 return searchPanel;
192 }
193
194 }), model) {
195
196 protected static final long serialVersionUID = -3056452800492734900L;
197
198 @Override
199 protected Component newTitle(final String markupId, final ITab tab, final Accordion.State state) {
200 return new AjaxLink<Integer>(markupId) {
201
202 protected static final long serialVersionUID = 6250423506463465679L;
203
204 @Override
205 public void onClick(final AjaxRequestTarget target) {
206 model.setObject(model.getObject() == 0 ? -1 : 0);
207 }
208 }.setBody(tab.getTitle()).setEscapeModelStrings(false);
209 }
210 };
211 accordion.setOutputMarkupId(true);
212 add(accordion.setEnabled(enableSearch).setVisible(enableSearch));
213
214 }
215
216 protected DirectoryPanelSupplier getDefaultDirectoryPanelSupplier() {
217 return (id, anyType, r, layout, pr) -> {
218 Panel panel;
219 String fiql;
220
221 String realm;
222 String dynRealm;
223 if (StringUtils.startsWith(r.getFullPath(), SyncopeConstants.ROOT_REALM)) {
224 realm = RealmsUtils.getFullPath(r.getFullPath());
225 dynRealm = null;
226 } else {
227 realm = SyncopeConstants.ROOT_REALM;
228 dynRealm = r.getKey();
229 }
230
231 switch (anyType.getKind()) {
232 case USER:
233 fiql = dynRealm == null
234 ? SyncopeClient.getUserSearchConditionBuilder().
235 is(Constants.KEY_FIELD_NAME).notNullValue().query()
236 : SyncopeClient.getUserSearchConditionBuilder().
237 inDynRealms(dynRealm).query();
238
239 UserTO user = new UserTO();
240 user.setRealm(RealmsUtils.getFullPath(r.getFullPath()));
241 panel = new UserDirectoryPanel.Builder(
242 anyTypeClassRestClient.list(anyType.getClasses()),
243 userRestClient,
244 anyType.getKey(),
245 pr).setRealm(realm).setDynRealm(dynRealm).setFiltered(true).
246 setFiql(fiql).setWizardInModal(true).addNewItemPanelBuilder(
247 AnyLayoutUtils.newLayoutInfo(
248 user, anyType.getClasses(), layout.getUser(), userRestClient, pr)).
249 build(id);
250 MetaDataRoleAuthorizationStrategy.authorize(panel, WebPage.RENDER,
251 IdRepoEntitlement.USER_SEARCH);
252 break;
253
254 case GROUP:
255 fiql = dynRealm == null
256 ? SyncopeClient.getGroupSearchConditionBuilder().
257 is(Constants.KEY_FIELD_NAME).notNullValue().query()
258 : SyncopeClient.getGroupSearchConditionBuilder().
259 inDynRealms(dynRealm).query();
260
261 GroupTO group = new GroupTO();
262 group.setRealm(RealmsUtils.getFullPath(r.getFullPath()));
263 panel = new GroupDirectoryPanel.Builder(
264 anyTypeClassRestClient.list(anyType.getClasses()),
265 groupRestClient,
266 anyType.getKey(),
267 pr).setRealm(realm).setDynRealm(dynRealm).setFiltered(true).
268 setFiql(fiql).setWizardInModal(true).addNewItemPanelBuilder(
269 AnyLayoutUtils.newLayoutInfo(
270 group, anyType.getClasses(), layout.getGroup(), groupRestClient, pr)).
271 build(id);
272
273 break;
274
275 case ANY_OBJECT:
276 fiql = dynRealm == null
277 ? SyncopeClient.getAnyObjectSearchConditionBuilder(anyType.getKey()).
278 is(Constants.KEY_FIELD_NAME).notNullValue().query()
279 : SyncopeClient.getAnyObjectSearchConditionBuilder(anyType.getKey()).
280 inDynRealms(dynRealm).query();
281
282 AnyObjectTO anyObject = new AnyObjectTO();
283 anyObject.setRealm(RealmsUtils.getFullPath(r.getFullPath()));
284 anyObject.setType(anyType.getKey());
285 panel = new AnyObjectDirectoryPanel.Builder(
286 anyTypeClassRestClient.list(anyType.getClasses()),
287 anyObjectRestClient,
288 anyType.getKey(),
289 pr).setRealm(realm).setDynRealm(dynRealm).setFiltered(true).
290 setFiql(fiql).setWizardInModal(true).addNewItemPanelBuilder(
291 AnyLayoutUtils.newLayoutInfo(anyObject, anyType.getClasses(),
292 layout.getAnyObjects().get(anyType.getKey()),
293 anyObjectRestClient, pr)).
294 build(id);
295 MetaDataRoleAuthorizationStrategy.authorize(
296 panel, WebPage.RENDER, AnyEntitlement.SEARCH.getFor(anyType.getKey()));
297 break;
298
299 default:
300 panel = new LabelPanel(id, null);
301 }
302 return panel;
303 };
304 }
305
306 protected Panel createDirectoryPanel(
307 final AnyTypeTO anyTypeTO,
308 final RealmTO realmTO,
309 final AnyLayout anyLayout,
310 final DirectoryPanelSupplier directoryPanelSupplier) {
311
312 return directoryPanelSupplier.supply(DIRECTORY_PANEL_ID, anyTypeTO, realmTO, anyLayout, pageRef);
313 }
314
315 @Override
316 public void onEvent(final IEvent<?> event) {
317 if (event.getPayload() instanceof SearchClausePanel.SearchEvent) {
318 AjaxRequestTarget target = SearchClausePanel.SearchEvent.class.cast(event.getPayload()).getTarget();
319
320 send(AnyPanel.this.directoryPanel, Broadcast.BREADTH,
321 new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target));
322
323 String precond = realmTO.getFullPath().startsWith(SyncopeConstants.ROOT_REALM)
324 ? StringUtils.EMPTY
325 : String.format("$dynRealms=~%s;", realmTO.getKey());
326
327 switch (anyTypeTO.getKind()) {
328 case USER:
329 UserDirectoryPanel.class.cast(AnyPanel.this.directoryPanel).search(
330 precond + SearchUtils.buildFIQL(
331 AnyPanel.this.searchPanel.getModel().getObject(),
332 SyncopeClient.getUserSearchConditionBuilder(),
333 AnyPanel.this.searchPanel.getAvailableSchemaTypes(),
334 SearchUtils.NO_CUSTOM_CONDITION),
335 target);
336 break;
337
338 case GROUP:
339 GroupDirectoryPanel.class.cast(AnyPanel.this.directoryPanel).search(
340 precond + SearchUtils.buildFIQL(
341 AnyPanel.this.searchPanel.getModel().getObject(),
342 SyncopeClient.getGroupSearchConditionBuilder(),
343 AnyPanel.this.searchPanel.getAvailableSchemaTypes(),
344 SearchUtils.NO_CUSTOM_CONDITION),
345 target);
346 break;
347
348 case ANY_OBJECT:
349 AnyObjectDirectoryPanel.class.cast(AnyPanel.this.directoryPanel).search(
350 precond + SearchUtils.buildFIQL(
351 AnyPanel.this.searchPanel.getModel().getObject(),
352 SyncopeClient.getAnyObjectSearchConditionBuilder(anyTypeTO.getKey()),
353 AnyPanel.this.searchPanel.getAvailableSchemaTypes(),
354 SearchUtils.NO_CUSTOM_CONDITION),
355 target);
356 break;
357
358 default:
359 }
360 } else {
361 super.onEvent(event);
362 }
363 }
364
365 protected AbstractSearchPanel getSearchPanel(final String id) {
366 List<SearchClause> clauses = new ArrayList<>();
367 SearchClause clause = new SearchClause();
368 clauses.add(clause);
369
370 AbstractSearchPanel panel;
371 switch (anyTypeTO.getKind()) {
372 case USER:
373 clause.setComparator(SearchClause.Comparator.EQUALS);
374 clause.setType(SearchClause.Type.ATTRIBUTE);
375 clause.setProperty(Constants.USERNAME_FIELD_NAME);
376
377 panel = new UserSearchPanel.Builder(
378 new ListModel<>(clauses), pageRef).required(true).enableSearch().build(id);
379 break;
380
381 case GROUP:
382 clause.setComparator(SearchClause.Comparator.EQUALS);
383 clause.setType(SearchClause.Type.ATTRIBUTE);
384 clause.setProperty(Constants.NAME_FIELD_NAME);
385
386 panel = new GroupSearchPanel.Builder(
387 new ListModel<>(clauses), pageRef).required(true).enableSearch().build(id);
388 break;
389
390 case ANY_OBJECT:
391 clause.setComparator(SearchClause.Comparator.EQUALS);
392 clause.setType(SearchClause.Type.ATTRIBUTE);
393 clause.setProperty(Constants.NAME_FIELD_NAME);
394
395 panel = new AnyObjectSearchPanel.Builder(anyTypeTO.getKey(),
396 new ListModel<>(clauses), pageRef).required(true).enableSearch().build(id);
397 break;
398
399 default:
400 panel = null;
401 }
402
403 return panel;
404 }
405 }