1 package com.atlassian.user.search.query;
2
3 import com.atlassian.user.*;
4 import com.atlassian.user.configuration.Configuration;
5 import com.atlassian.user.configuration.ConfigurationException;
6 import com.atlassian.user.configuration.util.InitializationCheck;
7 import com.atlassian.user.repository.RepositoryIdentifier;
8 import com.atlassian.user.search.DefaultSearchResult;
9 import com.atlassian.user.search.SearchResult;
10 import com.atlassian.user.search.query.match.*;
11 import com.atlassian.user.search.page.DefaultPager;
12 import com.atlassian.user.search.page.Pager;
13 import com.atlassian.user.search.page.PagerUtils;
14 import org.apache.commons.lang.StringUtils;
15 import org.apache.log4j.Logger;
16
17 import java.lang.reflect.InvocationTargetException;
18 import java.lang.reflect.Method;
19 import java.util.*;
20
21
22
23
24
25 public class DefaultEntityQueryParser implements EntityQueryParser
26 {
27 private static final Logger log = Logger.getLogger(DefaultEntityQueryParser.class);
28 private final QueryValidator queryValidator = new QueryValidator();
29
30 protected UserManager userManager;
31 protected GroupManager groupManager;
32 protected RepositoryIdentifier repository;
33 protected Method entityNameMethod;
34 protected Method emailMethod;
35 protected Method fullnameMethod;
36 private static final Class<User> userClass = User.class;
37
38 public DefaultEntityQueryParser(RepositoryIdentifier repo, UserManager userManager, GroupManager groupManager)
39 {
40 try
41 {
42 entityNameMethod = userClass.getMethod("getName");
43 emailMethod = userClass.getMethod("getEmail");
44 fullnameMethod = userClass.getMethod("getFullName");
45 }
46 catch (NoSuchMethodException e)
47 {
48 log.error(e.getMessage());
49 }
50
51 this.userManager = userManager;
52 this.groupManager = groupManager;
53 this.repository = repo;
54 }
55
56 public void init(HashMap args) throws ConfigurationException
57 {
58 this.userManager = (UserManager) args.get(Configuration.USERMANAGER);
59 this.groupManager = (GroupManager) args.get(Configuration.GROUPMANAGER);
60 this.repository = (RepositoryIdentifier) args.get(Configuration.REPOSITORY);
61
62 InitializationCheck.validateArgs(args, new String[]{Configuration.USERMANAGER,
63 Configuration.GROUPMANAGER,
64 Configuration.REPOSITORY}, this);
65
66 try
67 {
68 entityNameMethod = userClass.getMethod("getName");
69 emailMethod = userClass.getMethod("getEmail");
70 fullnameMethod = userClass.getMethod("getFullName");
71 }
72 catch (NoSuchMethodException e)
73 {
74 log.error(e.getMessage());
75 }
76 }
77
78 protected Pager<? extends Entity> parseQuery(Method userMethod, TermQuery q, Pager<? extends Entity> data) throws IllegalAccessException, InvocationTargetException
79 {
80 String searchTerm = StringUtils.defaultString(q.getTerm()).toLowerCase();
81 if (searchTerm.indexOf(TermQuery.WILDCARD) >= 0)
82 return data;
83
84 Matcher matcher;
85 if (q.isMatchingSubstring())
86 {
87 if (q.getMatchingRule().equals(TermQuery.SUBSTRING_STARTS_WITH))
88 {
89 matcher = new StartsWithIgnoreCaseMatcher();
90 }
91 else if (q.getMatchingRule().equals(TermQuery.SUBSTRING_ENDS_WITH))
92 {
93 matcher = new EndsWithIgnoreCaseMatcher();
94 }
95 else
96 {
97 matcher = new ContainsIgnoreCaseMatcher();
98 }
99 }
100 else
101 {
102 matcher = new EqualsIgnoreCaseMatcher();
103 }
104
105 List<Entity> matches = new ArrayList<Entity>();
106
107 for (Entity entity : data)
108 {
109 String userInfo = (String) userMethod.invoke(entity);
110
111 if (matcher.matches(userInfo, searchTerm))
112 matches.add(entity);
113 }
114 return new DefaultPager<Entity>(matches);
115 }
116
117 public Pager find(Query query) throws EntityException
118 {
119 Pager<? extends Entity> result = null;
120
121 if (query instanceof TermQuery)
122 {
123 try
124 {
125 if (query instanceof UserNameTermQuery)
126 result = parseQuery(entityNameMethod, (TermQuery) query, userManager.getUsers());
127 else if (query instanceof GroupNameTermQuery)
128 result = parseQuery(entityNameMethod, (TermQuery) query, groupManager.getGroups());
129 else if (query instanceof EmailTermQuery)
130 result = parseQuery(emailMethod, (TermQuery) query, userManager.getUsers());
131 else if (query instanceof FullNameTermQuery)
132 result = parseQuery(fullnameMethod, (TermQuery) query, userManager.getUsers());
133 }
134 catch (IllegalAccessException e)
135 {
136 throw new EntityException(e);
137 }
138 catch (InvocationTargetException e)
139 {
140 throw new EntityException(e);
141 }
142 }
143 else if (query instanceof MembershipQuery)
144 {
145 result = parseMembershipQuery(query);
146 }
147 else if (query instanceof BooleanQuery)
148 {
149 BooleanQuery bQuery = (BooleanQuery) query;
150 result = evaluateBoolean(bQuery);
151 }
152
153 return result;
154 }
155
156 private Pager<? extends Entity> parseMembershipQuery(Query query) throws EntityException
157 {
158 Pager<? extends Entity> result = null;
159
160 if (query instanceof UsersInGroupTwoTermQuery)
161 {
162 result = parseUsersInGroupTwoTermQuery((UsersInGroupTwoTermQuery) query);
163 }
164 else if (query instanceof GroupsOfUserTwoTermQuery)
165 {
166 result = parseGroupsOfUserTwoTermQuery((GroupsOfUserTwoTermQuery) query);
167 }
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 return result;
200 }
201
202 private Pager parseUsersInGroupTwoTermQuery(UsersInGroupTwoTermQuery query) throws EntityException
203 {
204 UserNameTermQuery userQuery = query.getUserNameTermQuery();
205 GroupNameTermQuery groupQuery = query.getGroupNameTermQuery();
206
207 Pager<User> users = find(userQuery);
208 Pager<Group> groups = find(groupQuery);
209
210 Iterator groupsIter = groups.iterator();
211 Set<String> candidateUsers = new HashSet<String>();
212
213 while (groupsIter.hasNext())
214 {
215 Group group = (Group) groupsIter.next();
216 candidateUsers.addAll(PagerUtils.toList(groupManager.getLocalMemberNames(group)));
217 }
218
219 List userQueryList = PagerUtils.toList(users);
220
221 userQueryList.retainAll(candidateUsers);
222
223 return new DefaultPager(userQueryList);
224 }
225
226 private Pager<? extends Entity> evaluateBoolean(BooleanQuery query) throws EntityException
227 {
228 List queries = query.getQueries();
229 Pager<? extends Entity> allResults = null;
230
231 if (query instanceof MembershipQuery)
232 {
233 return parseMembershipQuery(query);
234 }
235
236 boolean anding = query.isAND();
237
238 for (int i = 0; i < queries.size(); i++)
239 {
240 Query nextQuery = (Query) queries.get(i);
241 List initialResult;
242
243 try
244 {
245 if (allResults == null)
246 {
247 allResults = find(nextQuery);
248 }
249 else if (nextQuery instanceof BooleanQuery)
250 {
251 if (anding)
252 {
253 Pager<? extends Entity> resultsToAnd = evaluateBoolean((BooleanQuery) nextQuery);
254 List<? extends Entity> allResultsList = PagerUtils.toList(allResults);
255
256 List<Entity> resultsToAndList = new ArrayList<Entity>(PagerUtils.toList(resultsToAnd));
257 resultsToAndList.retainAll(allResultsList);
258 allResults = new DefaultPager<Entity>(resultsToAndList);
259 }
260 else
261 {
262 Pager<? extends Entity> resultsToOr = evaluateBoolean((BooleanQuery) nextQuery);
263 List<Entity> resultsToOrList = new ArrayList<Entity>(PagerUtils.toList(resultsToOr));
264 List<Entity> intersection = findIntersection(PagerUtils.toList(allResults), resultsToOrList);
265 allResults = new DefaultPager<Entity>(intersection);
266 }
267 }
268 else if (anding)
269 {
270
271 if (nextQuery instanceof UserNameTermQuery)
272 {
273 initialResult = PagerUtils.toList(parseQuery(entityNameMethod, (TermQuery) nextQuery,
274 allResults));
275 initialResult.addAll(PagerUtils.toList(allResults));
276 allResults = new DefaultPager(initialResult);
277 }
278 else if (nextQuery instanceof GroupNameTermQuery)
279 {
280 initialResult = PagerUtils.toList(parseQuery(entityNameMethod, (TermQuery) nextQuery,
281 allResults));
282 initialResult.addAll(PagerUtils.toList(allResults));
283 allResults = new DefaultPager(initialResult);
284 }
285 else if (nextQuery instanceof EmailTermQuery)
286 {
287 initialResult = PagerUtils.toList(parseQuery(emailMethod, (TermQuery) nextQuery, allResults));
288 initialResult.addAll(PagerUtils.toList(allResults));
289 allResults = new DefaultPager(initialResult);
290 }
291 else if (nextQuery instanceof FullNameTermQuery)
292 {
293 initialResult = PagerUtils.toList(parseQuery(fullnameMethod, (TermQuery) nextQuery,
294 allResults));
295 initialResult.addAll(PagerUtils.toList(allResults));
296 allResults = new DefaultPager(initialResult);
297 }
298 }
299 else
300 {
301 initialResult = PagerUtils.toList(find(nextQuery));
302 List intersection = findIntersection(PagerUtils.toList(allResults), initialResult);
303 allResults = new DefaultPager(intersection);
304 }
305 }
306 catch (Exception e)
307 {
308 log.error(e.getClass().getName() + " - " + e.getMessage());
309 }
310 }
311
312 return allResults;
313 }
314
315 private <T> List<T> findIntersection(List<? extends T> list1, List<? extends T> list2)
316 {
317 List<T> result = new ArrayList<T>(list1);
318
319 list2.removeAll(list1);
320 result.addAll(list2);
321
322 return result;
323 }
324
325 private Pager parseGroupsOfUserTwoTermQuery(GroupsOfUserTwoTermQuery query) throws EntityException
326 {
327 UserNameTermQuery userQuery = query.getUserNameTermQuery();
328 GroupNameTermQuery groupQuery = query.getGroupNameTermQuery();
329
330 Pager groups = find(groupQuery);
331 Pager users = find(userQuery);
332
333 Iterator usersIter = users.iterator();
334 Set<Group> candidateGroups = new HashSet<Group>();
335
336 while (usersIter.hasNext())
337 {
338 User user = (User) usersIter.next();
339 candidateGroups.addAll(PagerUtils.toList(groupManager.getGroups(user)));
340 }
341
342 List groupQueryList = PagerUtils.toList(groups);
343
344 groupQueryList.retainAll(candidateGroups);
345
346 return new DefaultPager(groupQueryList);
347 }
348
349 public SearchResult findUsers(Query query) throws EntityException
350 {
351 queryValidator.assertValid(query);
352 Pager pager = find(query);
353 return new DefaultSearchResult(pager, repository.getKey());
354 }
355
356 public SearchResult findGroups(Query query) throws EntityException
357 {
358 queryValidator.assertValid(query);
359 Pager pager = find(query);
360 return new DefaultSearchResult(pager, repository.getKey());
361 }
362
363 public SearchResult findUsers(Query query, QueryContext context) throws EntityException
364 {
365 if (!context.contains(repository))
366 return null;
367
368 queryValidator.assertValid(query);
369 return findUsers(query);
370 }
371
372 public SearchResult findGroups(Query query, QueryContext context) throws EntityException
373 {
374 if (!context.contains(repository))
375 return null;
376
377 queryValidator.assertValid(query);
378 return findGroups(query);
379 }
380 }