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