1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.core.persistence.api.search;
20
21 import java.net.URLDecoder;
22 import java.nio.charset.StandardCharsets;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Optional;
26 import java.util.regex.Pattern;
27 import org.apache.cxf.jaxrs.ext.search.ConditionType;
28 import org.apache.cxf.jaxrs.ext.search.SearchBean;
29 import org.apache.cxf.jaxrs.ext.search.SearchCondition;
30 import org.apache.cxf.jaxrs.ext.search.SearchUtils;
31 import org.apache.cxf.jaxrs.ext.search.visitor.AbstractSearchConditionVisitor;
32 import org.apache.syncope.common.lib.search.SearchableFields;
33 import org.apache.syncope.common.lib.search.SpecialAttr;
34 import org.apache.syncope.common.lib.search.SyncopeFiqlParser;
35 import org.apache.syncope.common.lib.search.SyncopeFiqlSearchCondition;
36 import org.apache.syncope.core.persistence.api.dao.search.AnyCond;
37 import org.apache.syncope.core.persistence.api.dao.search.AnyTypeCond;
38 import org.apache.syncope.core.persistence.api.dao.search.AttrCond;
39 import org.apache.syncope.core.persistence.api.dao.search.AuxClassCond;
40 import org.apache.syncope.core.persistence.api.dao.search.DynRealmCond;
41 import org.apache.syncope.core.persistence.api.dao.search.MemberCond;
42 import org.apache.syncope.core.persistence.api.dao.search.MembershipCond;
43 import org.apache.syncope.core.persistence.api.dao.search.PrivilegeCond;
44 import org.apache.syncope.core.persistence.api.dao.search.RelationshipCond;
45 import org.apache.syncope.core.persistence.api.dao.search.RelationshipTypeCond;
46 import org.apache.syncope.core.persistence.api.dao.search.ResourceCond;
47 import org.apache.syncope.core.persistence.api.dao.search.RoleCond;
48 import org.apache.syncope.core.persistence.api.dao.search.SearchCond;
49
50
51
52
53 public class SearchCondVisitor extends AbstractSearchConditionVisitor<SearchBean, SearchCond> {
54
55 protected static final Pattern TIMEZONE = Pattern.compile(".* [0-9]{4}$");
56
57 protected static final ThreadLocal<String> REALM = new ThreadLocal<>();
58
59 protected static final ThreadLocal<SearchCond> SEARCH_COND = new ThreadLocal<>();
60
61 public SearchCondVisitor() {
62 super(null);
63 }
64
65 public void setRealm(final String realm) {
66 REALM.set(realm);
67 }
68
69 protected static AttrCond createAttrCond(final String schema) {
70 AttrCond attrCond = SearchableFields.contains(schema)
71 ? new AnyCond()
72 : new AttrCond();
73 attrCond.setSchema(schema);
74 return attrCond;
75 }
76
77 protected static String getValue(final SearchCondition<SearchBean> sc) {
78 String value = SearchUtils.toSqlWildcardString(
79 URLDecoder.decode(sc.getStatement().getValue().toString(), StandardCharsets.UTF_8), false);
80 if (value.indexOf('%') == -1) {
81 value = value.replaceAll("\\\\_", "_");
82 }
83
84 if (TIMEZONE.matcher(value).matches()) {
85 char[] valueAsArray = value.toCharArray();
86 valueAsArray[valueAsArray.length - 5] = '+';
87 value = new String(valueAsArray);
88 }
89
90 return value;
91 }
92
93 protected static ConditionType getConditionType(final SearchCondition<SearchBean> sc) {
94 ConditionType ct = sc.getConditionType();
95 if (sc instanceof SyncopeFiqlSearchCondition && sc.getConditionType() == ConditionType.CUSTOM) {
96 SyncopeFiqlSearchCondition<SearchBean> sfsc = (SyncopeFiqlSearchCondition<SearchBean>) sc;
97 switch (sfsc.getOperator()) {
98 case SyncopeFiqlParser.IEQ:
99 ct = ConditionType.EQUALS;
100 break;
101
102 case SyncopeFiqlParser.NIEQ:
103 ct = ConditionType.NOT_EQUALS;
104 break;
105
106 default:
107 throw new IllegalArgumentException(
108 String.format("Condition type %s is not supported", sfsc.getOperator()));
109 }
110 }
111
112 return ct;
113 }
114
115 @SuppressWarnings("ConvertToStringSwitch")
116 protected SearchCond visitPrimitive(final SearchCondition<SearchBean> sc) {
117 String name = getRealPropertyName(sc.getStatement().getProperty());
118 Optional<SpecialAttr> specialAttrName = SpecialAttr.fromString(name);
119
120 String value = getValue(sc);
121 Optional<SpecialAttr> specialAttrValue = SpecialAttr.fromString(value);
122
123 AttrCond attrCond = createAttrCond(name);
124 attrCond.setExpression(value);
125
126 ConditionType ct = getConditionType(sc);
127
128 SearchCond leaf;
129 switch (ct) {
130 case EQUALS:
131 case NOT_EQUALS:
132 if (specialAttrName.isEmpty()) {
133 if (specialAttrValue.isPresent() && specialAttrValue.get() == SpecialAttr.NULL) {
134 attrCond.setType(AttrCond.Type.ISNULL);
135 attrCond.setExpression(null);
136 } else if (value.indexOf('%') == -1) {
137 attrCond.setType(sc.getConditionType() == ConditionType.CUSTOM
138 ? AttrCond.Type.IEQ
139 : AttrCond.Type.EQ);
140 } else {
141 attrCond.setType(sc.getConditionType() == ConditionType.CUSTOM
142 ? AttrCond.Type.ILIKE
143 : AttrCond.Type.LIKE);
144 }
145
146 leaf = SearchCond.getLeaf(attrCond);
147 } else {
148 switch (specialAttrName.get()) {
149 case TYPE:
150 AnyTypeCond typeCond = new AnyTypeCond();
151 typeCond.setAnyTypeKey(value);
152 leaf = SearchCond.getLeaf(typeCond);
153 break;
154
155 case AUX_CLASSES:
156 AuxClassCond auxClassCond = new AuxClassCond();
157 auxClassCond.setAuxClass(value);
158 leaf = SearchCond.getLeaf(auxClassCond);
159 break;
160
161 case RESOURCES:
162 ResourceCond resourceCond = new ResourceCond();
163 resourceCond.setResource(value);
164 leaf = SearchCond.getLeaf(resourceCond);
165 break;
166
167 case GROUPS:
168 MembershipCond groupCond = new MembershipCond();
169 groupCond.setGroup(value);
170 leaf = SearchCond.getLeaf(groupCond);
171 break;
172
173 case RELATIONSHIPS:
174 RelationshipCond relationshipCond = new RelationshipCond();
175 relationshipCond.setAnyObject(value);
176 leaf = SearchCond.getLeaf(relationshipCond);
177 break;
178
179 case RELATIONSHIP_TYPES:
180 RelationshipTypeCond relationshipTypeCond = new RelationshipTypeCond();
181 relationshipTypeCond.setRelationshipTypeKey(value);
182 leaf = SearchCond.getLeaf(relationshipTypeCond);
183 break;
184
185 case ROLES:
186 RoleCond roleCond = new RoleCond();
187 roleCond.setRole(value);
188 leaf = SearchCond.getLeaf(roleCond);
189 break;
190
191 case PRIVILEGES:
192 PrivilegeCond privilegeCond = new PrivilegeCond();
193 privilegeCond.setPrivilege(value);
194 leaf = SearchCond.getLeaf(privilegeCond);
195 break;
196
197 case DYNREALMS:
198 DynRealmCond dynRealmCond = new DynRealmCond();
199 dynRealmCond.setDynRealm(value);
200 leaf = SearchCond.getLeaf(dynRealmCond);
201 break;
202
203 case MEMBER:
204 MemberCond memberCond = new MemberCond();
205 memberCond.setMember(value);
206 leaf = SearchCond.getLeaf(memberCond);
207 break;
208
209 default:
210 throw new IllegalArgumentException(
211 String.format("Special attr name %s is not supported", specialAttrName));
212 }
213 }
214 if (ct == ConditionType.NOT_EQUALS) {
215 Optional<AttrCond> notEquals = leaf.getLeaf(AttrCond.class);
216 if (notEquals.isPresent() && notEquals.get().getType() == AttrCond.Type.ISNULL) {
217 notEquals.get().setType(AttrCond.Type.ISNOTNULL);
218 } else {
219 leaf = SearchCond.getNotLeaf(leaf);
220 }
221 }
222 break;
223
224 case GREATER_OR_EQUALS:
225 attrCond.setType(AttrCond.Type.GE);
226 leaf = SearchCond.getLeaf(attrCond);
227 break;
228
229 case GREATER_THAN:
230 attrCond.setType(AttrCond.Type.GT);
231 leaf = SearchCond.getLeaf(attrCond);
232 break;
233
234 case LESS_OR_EQUALS:
235 attrCond.setType(AttrCond.Type.LE);
236 leaf = SearchCond.getLeaf(attrCond);
237 break;
238
239 case LESS_THAN:
240 attrCond.setType(AttrCond.Type.LT);
241 leaf = SearchCond.getLeaf(attrCond);
242 break;
243
244 default:
245 throw new IllegalArgumentException(String.format("Condition type %s is not supported", ct.name()));
246 }
247
248
249 Optional<AttrCond> reprocess = leaf.getLeaf(AttrCond.class).
250 filter(cond -> "token".equals(cond.getSchema())
251 && (cond.getType() == AttrCond.Type.ISNULL || cond.getType() == AttrCond.Type.ISNOTNULL)
252 && cond.getExpression() == null);
253 if (reprocess.isPresent()) {
254 AnyCond tokenCond = new AnyCond();
255 tokenCond.setSchema(reprocess.get().getSchema());
256 tokenCond.setType(reprocess.get().getType());
257 tokenCond.setExpression(null);
258 leaf = SearchCond.getLeaf(tokenCond);
259 }
260
261 return leaf;
262 }
263
264 protected SearchCond visitCompound(final SearchCondition<SearchBean> sc) {
265 List<SearchCond> searchConds = new ArrayList<>();
266 sc.getSearchConditions().forEach(searchCond -> {
267 searchConds.add(searchCond.getStatement() == null
268 ? visitCompound(searchCond)
269 : visitPrimitive(searchCond));
270 });
271
272 SearchCond compound;
273 switch (sc.getConditionType()) {
274 case AND:
275 compound = SearchCond.getAnd(searchConds);
276 break;
277
278 case OR:
279 compound = SearchCond.getOr(searchConds);
280 break;
281
282 default:
283 throw new IllegalArgumentException(
284 String.format("Condition type %s is not supported", sc.getConditionType().name()));
285 }
286
287 return compound;
288 }
289
290 @Override
291 public void visit(final SearchCondition<SearchBean> sc) {
292 SEARCH_COND.set(sc.getStatement() == null ? visitCompound(sc) : visitPrimitive(sc));
293 }
294
295 @Override
296 public SearchCond getQuery() {
297 return SEARCH_COND.get();
298 }
299 }