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.search;
20
21 import java.io.Serializable;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.stream.Collectors;
26 import org.apache.commons.lang3.StringUtils;
27 import org.apache.commons.lang3.tuple.Pair;
28 import org.apache.syncope.client.console.SyncopeConsoleSession;
29 import org.apache.syncope.client.console.SyncopeWebApplication;
30 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
31 import org.apache.syncope.client.console.rest.FIQLQueryRestClient;
32 import org.apache.syncope.client.console.rest.GroupRestClient;
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.wicket.markup.html.form.MultiFieldPanel;
36 import org.apache.syncope.common.lib.SyncopeConstants;
37 import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
38 import org.apache.syncope.common.lib.search.SearchableFields;
39 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
40 import org.apache.syncope.common.lib.to.PlainSchemaTO;
41 import org.apache.syncope.common.lib.types.AnyTypeKind;
42 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
43 import org.apache.wicket.PageReference;
44 import org.apache.wicket.ajax.AjaxRequestTarget;
45 import org.apache.wicket.event.IEventSink;
46 import org.apache.wicket.markup.html.WebMarkupContainer;
47 import org.apache.wicket.markup.html.panel.Panel;
48 import org.apache.wicket.model.IModel;
49 import org.apache.wicket.model.LoadableDetachableModel;
50 import org.apache.wicket.model.Model;
51 import org.apache.wicket.spring.injection.annot.SpringBean;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 public abstract class AbstractSearchPanel extends Panel {
56
57 private static final long serialVersionUID = 5922413053568696414L;
58
59 protected static final Logger LOG = LoggerFactory.getLogger(AbstractSearchPanel.class);
60
61 @SpringBean
62 protected AnyTypeClassRestClient anyTypeClassRestClient;
63
64 @SpringBean
65 protected FIQLQueryRestClient fiqlQueryRestClient;
66
67 @SpringBean
68 protected GroupRestClient groupRestClient;
69
70 protected IModel<Map<String, PlainSchemaTO>> dnames;
71
72 protected IModel<Map<String, PlainSchemaTO>> anames;
73
74 protected IModel<List<String>> auxClassNames;
75
76 protected IModel<List<String>> resourceNames;
77
78 protected IModel<List<SearchClause.Type>> types;
79
80 protected IModel<List<String>> groupNames;
81
82 protected IModel<List<String>> roleNames;
83
84 protected IModel<List<String>> privilegeNames;
85
86 protected IModel<List<SearchClause>> model;
87
88 protected WebMarkupContainer searchFormContainer;
89
90 protected final AnyTypeKind typeKind;
91
92 protected final String type;
93
94 public abstract static class Builder<T extends AbstractSearchPanel> implements Serializable {
95
96 private static final long serialVersionUID = 6308997285778809578L;
97
98 protected final IModel<List<SearchClause>> model;
99
100 protected PageReference pageRef;
101
102 protected boolean required = true;
103
104 protected boolean enableSearch = false;
105
106 protected SearchClausePanel.Customizer customizer = new SearchClausePanel.Customizer() {
107
108 private static final long serialVersionUID = 4449199405807453441L;
109
110 };
111
112 protected IEventSink resultContainer;
113
114 public Builder(final IModel<List<SearchClause>> model, final PageReference pageRef) {
115 this.model = model;
116 this.pageRef = pageRef;
117 }
118
119 public Builder<T> enableSearch(final IEventSink resultContainer) {
120 this.resultContainer = resultContainer;
121 return enableSearch();
122 }
123
124 public Builder<T> enableSearch() {
125 this.enableSearch = true;
126 return this;
127 }
128
129 public Builder<T> customizer(final SearchClausePanel.Customizer customizer) {
130 this.customizer = customizer;
131 return this;
132 }
133
134 public Builder<T> required(final boolean required) {
135 this.required = required;
136 return this;
137 }
138
139 public abstract T build(String id);
140 }
141
142 protected AbstractSearchPanel(final String id, final AnyTypeKind kind, final Builder<?> builder) {
143 this(id, kind, kind.name(), builder);
144 }
145
146 protected AbstractSearchPanel(
147 final String id, final AnyTypeKind kind, final String type, final Builder<?> builder) {
148
149 super(id);
150
151 populate();
152
153 this.model = builder.model;
154 this.typeKind = kind;
155 this.type = type;
156
157 setOutputMarkupId(true);
158
159 searchFormContainer = new WebMarkupContainer("searchFormContainer");
160 searchFormContainer.setOutputMarkupId(true);
161 add(searchFormContainer);
162
163 Pair<IModel<List<String>>, IModel<Integer>> groupInfo =
164 typeKind != AnyTypeKind.GROUP && SyncopeConsoleSession.get().owns(IdRepoEntitlement.GROUP_SEARCH)
165 ? Pair.of(groupNames, new LoadableDetachableModel<>() {
166
167 private static final long serialVersionUID = 7362833782319137329L;
168
169 @Override
170 protected Integer load() {
171 return groupRestClient.count(SyncopeConstants.ROOT_REALM, null, null);
172 }
173 })
174 : Pair.of(groupNames, Model.of(0));
175 SearchClausePanel searchClausePanel = new SearchClausePanel("panel", "panel",
176 Model.of(new SearchClause()),
177 builder.required,
178 types,
179 builder.customizer,
180 anames, dnames, groupInfo, roleNames, privilegeNames, auxClassNames, resourceNames);
181 if (builder.enableSearch) {
182 searchClausePanel.enableSearch(builder.resultContainer);
183 }
184
185 searchFormContainer.add(new MultiFieldPanel.Builder<>(model) {
186
187 private static final long serialVersionUID = 1343431509987473047L;
188
189 @Override
190 protected SearchClause newModelObject() {
191 return new SearchClause();
192 }
193 }.build("search", "search", searchClausePanel).hideLabel().setOutputMarkupId(true));
194
195 FIQLQueries fiqlQueries = new FIQLQueries(
196 "fiqlQueries", fiqlQueryRestClient, this, getFIQLQueryTarget(), builder.pageRef);
197 add(fiqlQueries);
198
199 SaveFIQLQuery saveFIQLQuery = new SaveFIQLQuery("saveFIQLQuery", getFIQLQueryTarget(), builder.pageRef);
200 add(saveFIQLQuery);
201
202 ActionsPanel<Serializable> fiqlQueryActionsPanel = new ActionsPanel<>("fiqlQueryActionsPanel", null);
203 fiqlQueryActionsPanel.add(new ActionLink<>() {
204
205 private static final long serialVersionUID = 2041211756396714619L;
206
207 @Override
208 public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
209 saveFIQLQuery.setFiql(
210 SearchUtils.buildFIQL(AbstractSearchPanel.this.getModel().getObject(),
211 getSearchConditionBuilder()).
212 replaceAll(SearchUtils.getTypeConditionPattern(type).pattern(), ""));
213 saveFIQLQuery.toggle(target, true);
214 }
215 }, ActionLink.ActionType.EXPORT, StringUtils.EMPTY).hideLabel();
216 fiqlQueryActionsPanel.add(new ActionLink<>() {
217
218 private static final long serialVersionUID = -7978723352517770644L;
219
220 @Override
221 public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
222 fiqlQueries.toggle(target, true);
223 }
224 }, ActionLink.ActionType.SELECT, StringUtils.EMPTY).hideLabel();
225 fiqlQueryActionsPanel.setVisible(
226 builder.enableSearch
227 && !model.getObject().isEmpty()
228 && !SyncopeConsoleSession.get().getSelfTO().getUsername().
229 equals(SyncopeWebApplication.get().getAdminUser()));
230 add(fiqlQueryActionsPanel.setOutputMarkupPlaceholderTag(true));
231 }
232
233 protected abstract AbstractFiqlSearchConditionBuilder<?, ?, ?> getSearchConditionBuilder();
234
235 protected abstract String getFIQLQueryTarget();
236
237 protected void updateFIQL(final AjaxRequestTarget target, final String fiql) {
238 model.setObject(SearchUtils.getSearchClauses(
239 fiql.replaceAll(SearchUtils.getTypeConditionPattern(type).pattern(), "")));
240 target.add(searchFormContainer);
241 }
242
243 protected void populate() {
244 dnames = new LoadableDetachableModel<>() {
245
246 private static final long serialVersionUID = 5275935387613157437L;
247
248 @Override
249 protected Map<String, PlainSchemaTO> load() {
250 Map<String, PlainSchemaTO> dSchemaNames = new HashMap<>();
251 SearchableFields.get(typeKind.getTOClass()).forEach((key, type) -> {
252 PlainSchemaTO plain = new PlainSchemaTO();
253 plain.setType(type);
254 dSchemaNames.put(key, plain);
255 });
256 return dSchemaNames;
257 }
258 };
259
260 auxClassNames = new LoadableDetachableModel<>() {
261
262 private static final long serialVersionUID = 5275935387613157437L;
263
264 @Override
265 protected List<String> load() {
266 return anyTypeClassRestClient.list().stream().
267 filter(c -> c.getInUseByTypes().isEmpty()).
268 map(AnyTypeClassTO::getKey).
269 collect(Collectors.toList());
270 }
271 };
272
273 resourceNames = new LoadableDetachableModel<>() {
274
275 private static final long serialVersionUID = 5275935387613157437L;
276
277 @Override
278 protected List<String> load() {
279 return SyncopeWebApplication.get().getResourceProvider().get();
280 }
281 };
282 }
283
284 public IModel<List<SearchClause>> getModel() {
285 return this.model;
286 }
287
288 public String getBackObjectType() {
289 return this.type;
290 }
291
292 public Map<String, PlainSchemaTO> getAvailableSchemaTypes() {
293 return anames.getObject();
294 }
295 }