1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.common.search.service.impl;
17
18 import java.text.SimpleDateFormat;
19 import java.util.ArrayList;
20 import java.util.Date;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.kuali.student.common.search.dto.CrossSearchTypeInfo;
26 import org.kuali.student.common.search.dto.JoinComparisonInfo;
27 import org.kuali.student.common.search.dto.JoinComparisonInfo.ComparisonType;
28 import org.kuali.student.common.search.dto.JoinCriteriaInfo;
29 import org.kuali.student.common.search.dto.JoinCriteriaInfo.JoinType;
30 import org.kuali.student.common.search.dto.JoinResultMappingInfo;
31 import org.kuali.student.common.search.dto.SearchParam;
32 import org.kuali.student.common.search.dto.SearchRequest;
33 import org.kuali.student.common.search.dto.SearchResult;
34 import org.kuali.student.common.search.dto.SearchResultCell;
35 import org.kuali.student.common.search.dto.SearchResultRow;
36 import org.kuali.student.common.search.dto.SubSearchInfo;
37 import org.kuali.student.common.search.dto.SubSearchParamMappingInfo;
38 import org.kuali.student.common.search.service.SearchDispatcher;
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class CrossSearchManager {
54 private SearchDispatcher searchDispatcher;
55
56 public SearchResult doCrossSearch(SearchRequest searchRequest, CrossSearchTypeInfo crossSearchType) {
57 SearchResult searchResult = new SearchResult();
58
59 Map<String,SearchResult> subSearchResults = new HashMap<String,SearchResult>();
60
61
62 for(SubSearchInfo subSearch:crossSearchType.getSubSearches()){
63
64 SearchRequest subSearchRequest = new SearchRequest();
65
66 subSearchRequest.setSearchKey(subSearch.getSearchkey());
67 subSearchRequest.setParams(new ArrayList<SearchParam>());
68 subSearchRequest.setSortColumn(searchRequest.getSortColumn());
69 subSearchRequest.setSortDirection(searchRequest.getSortDirection());
70
71
72 for(SubSearchParamMappingInfo paramMapping:subSearch.getSubSearchParamMappings()){
73 for(SearchParam crossSearchParam:searchRequest.getParams()){
74 if(paramMapping.getCrossSearchParam().equals(crossSearchParam.getKey())){
75 SearchParam subSearchParam = new SearchParam();
76 subSearchParam.setKey(paramMapping.getSubSearchParam());
77 Object paramValue = crossSearchParam.getValue();
78 if(paramValue instanceof String){
79 subSearchParam.setValue((String)paramValue);
80 }else if(paramValue instanceof List<?>){
81 subSearchParam.setValue((List<String>)paramValue);
82 }
83 subSearchRequest.getParams().add(subSearchParam);
84 }
85 }
86 }
87 SearchResult subSearchResult = searchDispatcher.dispatchSearch(subSearchRequest);
88 subSearchResults.put(subSearch.getKey(), subSearchResult);
89 }
90
91
92 if(crossSearchType.getJoinCriteria().getComparisons().isEmpty()){
93
94 for(Map.Entry<String,SearchResult> subSearchResult:subSearchResults.entrySet()){
95 for(SearchResultRow row:subSearchResult.getValue().getRows()){
96 SearchResultRow mappedResult = mapResultRow(subSearchResult.getKey(),row,crossSearchType);
97 searchResult.getRows().add(mappedResult);
98 }
99 }
100 }else{
101
102 List <Map<String,SearchResultRow>> allPermutations = unionOfAllRows(subSearchResults);
103
104 for(Map<String,SearchResultRow> permutation:allPermutations){
105 if(meetsCriteria(permutation,crossSearchType,crossSearchType.getJoinCriteria())){
106 SearchResultRow mappedResult = mapResultRow(permutation,crossSearchType);
107 searchResult.getRows().add(mappedResult);
108 }
109 }
110 }
111 return metaFilter(searchResult,searchRequest);
112 }
113
114
115
116
117
118
119
120
121
122 private SearchResult metaFilter(SearchResult searchResult,
123 SearchRequest searchRequest) {
124
125 searchResult.setTotalResults(searchResult.getRows().size());
126
127 searchResult.sortRows();
128
129
130 if(searchRequest.getMaxResults()!=null){
131 int fromIndex=0;
132 if(searchRequest.getStartAt()!=null){
133 fromIndex=searchRequest.getStartAt();
134 }
135 int toIndex = fromIndex+searchRequest.getMaxResults();
136 SearchResult pagedResult = new SearchResult();
137 for (int i=fromIndex; i <= toIndex; i++) {
138 if (!(searchResult.getRows().size() < i+1)) {
139 pagedResult.getRows().add(searchResult.getRows().get(i));
140 }
141 }
142 pagedResult.setTotalResults(searchResult.getRows().size());
143 searchResult = pagedResult;
144 }
145 return searchResult;
146 }
147
148
149
150
151
152
153
154
155 private SearchResultRow mapResultRow(
156 Map<String, SearchResultRow> permutation,
157 CrossSearchTypeInfo crossSearchType) {
158
159 SearchResultRow resultRow = new SearchResultRow();
160 for(JoinResultMappingInfo resultMapping: crossSearchType.getJoinResultMappings()){
161 for(SearchResultCell cell: permutation.get(resultMapping.getSubSearchKey()).getCells()){
162 if(resultMapping.getSubSearchResultParam().equals(cell.getKey())){
163 SearchResultCell mappedCell = new SearchResultCell();
164 mappedCell.setKey(resultMapping.getResultParam());
165 mappedCell.setValue(cell.getValue());
166 resultRow.getCells().add(mappedCell);
167 break;
168 }
169 }
170 }
171 return resultRow;
172
173 }
174
175 private SearchResultRow mapResultRow(
176 String subSearchKey, SearchResultRow row,
177 CrossSearchTypeInfo crossSearchType) {
178 SearchResultRow resultRow = new SearchResultRow();
179
180 for(JoinResultMappingInfo resultMapping: crossSearchType.getJoinResultMappings()){
181 if(subSearchKey.equals(resultMapping.getSubSearchKey())){
182 for(SearchResultCell cell: row.getCells()){
183 if(resultMapping.getSubSearchResultParam().equals(cell.getKey())){
184 SearchResultCell mappedCell = new SearchResultCell();
185 mappedCell.setKey(resultMapping.getResultParam());
186 mappedCell.setValue(cell.getValue());
187 resultRow.getCells().add(mappedCell);
188 break;
189 }
190 }
191 }
192 }
193 return resultRow;
194 }
195
196
197
198
199
200
201
202
203 private boolean meetsCriteria(Map<String, SearchResultRow> permutation,
204 CrossSearchTypeInfo crossSearchType, JoinCriteriaInfo joinCriteria){
205
206 JoinType joinType = joinCriteria.getJoinType();
207
208
209 for(JoinComparisonInfo comparison:joinCriteria.getComparisons()){
210 SearchResultRow leftResultRow = permutation.get(comparison.getLeftHandSide().getSubSearchKey());
211 String leftResultValue = null;
212 if(leftResultRow!=null){
213 for(SearchResultCell cell: leftResultRow.getCells()){
214 if(comparison.getLeftHandSide().getParam().equals(cell.getKey())){
215 leftResultValue = cell.getValue();
216 break;
217 }
218 }
219 }
220
221 SearchResultRow rightResultRow = permutation.get(comparison.getRightHandSide().getSubSearchKey());
222 String rightResultValue = null;
223 if(rightResultRow!=null){
224 for(SearchResultCell cell: rightResultRow.getCells()){
225 if(comparison.getRightHandSide().getParam().equals(cell.getKey())){
226 rightResultValue = cell.getValue();
227 break;
228 }
229 }
230 }
231
232
233
234 if(leftResultValue==null||rightResultValue==null){
235 int i=0;i++;
236 }
237 if(compare(null, leftResultValue,rightResultValue,comparison.getType())){
238 if(JoinType.OR.equals(joinType)){
239 return true;
240 }
241 }else{
242 if(JoinType.AND.equals(joinType)){
243 return false;
244 }
245 }
246 }
247
248
249 for(JoinCriteriaInfo subCriteria: joinCriteria.getJoinCriteria()){
250 if(meetsCriteria(permutation, crossSearchType, subCriteria)){
251 if(JoinType.OR.equals(joinType)){
252 return true;
253 }
254 }else{
255 if(JoinType.AND.equals(joinType)){
256 return false;
257 }
258 }
259 }
260
261 if(JoinType.AND.equals(joinType)){
262 return true;
263 }
264 if(JoinType.OR.equals(joinType)){
265 return false;
266 }
267
268 return false;
269 }
270
271
272
273
274
275 private List <Map<String,SearchResultRow>> unionOfAllRows(Map<String, SearchResult> searchResults){
276 List <Map<String,SearchResultRow>> r = new ArrayList<Map<String,SearchResultRow>>();
277 for(Map.Entry<String,SearchResult> x:searchResults.entrySet()){
278 List<Map<String,SearchResultRow>> t = new ArrayList<Map<String,SearchResultRow>>();
279 if(x.getValue()!=null&&x.getValue().getRows()!=null){
280 for(SearchResultRow y:x.getValue().getRows()){
281 for(Map<String,SearchResultRow> i:r){
282 Map<String,SearchResultRow> unions = new HashMap<String,SearchResultRow>();
283 unions.putAll(i);
284 unions.put(x.getKey(), y);
285 t.add(unions);
286 }
287 if(r.size()==0){
288 Map<String,SearchResultRow> unions = new HashMap<String,SearchResultRow>();
289 unions.put(x.getKey(), y);
290 t.add(unions);
291 }
292 }
293 }
294 r = t;
295 }
296 return r;
297 }
298
299 private enum DataType{STRING,INT,BOOLEAN,DATE}
300
301
302
303 private boolean compare(DataType dataType, String left, String right,
304 ComparisonType type ){
305
306 try{
307 Integer leftInteger = Integer.parseInt(left);
308 Integer rightInteger = Integer.parseInt(right);
309 return compareInt(leftInteger,rightInteger,type);
310 }catch(Exception e){
311 }
312 try{
313 if(("true".equals(left.toLowerCase())||"false".equals(left.toLowerCase()))&&
314 ("true".equals(right.toLowerCase())||"false".equals(right.toLowerCase()))){
315 Boolean leftBoolean = Boolean.parseBoolean(left);
316 Boolean rightBoolean = Boolean.parseBoolean(right);
317 return compareBoolean(leftBoolean,rightBoolean,type);
318 }
319 }catch(Exception e){
320 }
321 try{
322 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
323 Date leftDate = df.parse(left);
324 Date rightDate = df.parse(right);
325 return compareDate(leftDate,rightDate,type);
326 }catch(Exception e){
327 }
328 return compareString(left,right,type);
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347 }
348
349 private boolean compareString(String left, String right, ComparisonType type) {
350 switch(type){
351 case EQUALS:
352 return left.equals(right);
353 case GREATERTHAN:
354 return left.compareTo(right) > 0;
355 case GREATERTHANEQUALS:
356 return left.compareTo(right) >= 0;
357 case LESSTHAN:
358 return left.compareTo(right) < 0;
359 case LESSTHANEQUALS:
360 return left.compareTo(right) <= 0;
361 case NOTEQUALS:
362 return !left.equals(right);
363 }
364 return false;
365 }
366
367 private boolean compareInt(Integer left, Integer right, ComparisonType type) {
368 switch(type){
369 case EQUALS:
370 return left.equals(right);
371 case GREATERTHAN:
372 return left.compareTo(right) > 0;
373 case GREATERTHANEQUALS:
374 return left.compareTo(right) >= 0;
375 case LESSTHAN:
376 return left.compareTo(right) < 0;
377 case LESSTHANEQUALS:
378 return left.compareTo(right) <= 0;
379 case NOTEQUALS:
380 return !left.equals(right);
381 }
382 return false;
383 }
384
385 private boolean compareDate(Date left, Date right, ComparisonType type) {
386 switch(type){
387 case EQUALS:
388 return left.equals(right);
389 case GREATERTHAN:
390 return left.compareTo(right) > 0;
391 case GREATERTHANEQUALS:
392 return left.compareTo(right) >= 0;
393 case LESSTHAN:
394 return left.compareTo(right) < 0;
395 case LESSTHANEQUALS:
396 return left.compareTo(right) <= 0;
397 case NOTEQUALS:
398 return !left.equals(right);
399 }
400 return false;
401 }
402
403 private boolean compareBoolean(Boolean left, Boolean right,
404 ComparisonType type) {
405 switch(type){
406 case EQUALS:
407 return left.equals(right);
408 case GREATERTHAN:
409 return left.compareTo(right) > 0;
410 case GREATERTHANEQUALS:
411 return left.compareTo(right) >= 0;
412 case LESSTHAN:
413 return left.compareTo(right) < 0;
414 case LESSTHANEQUALS:
415 return left.compareTo(right) <= 0;
416 case NOTEQUALS:
417 return !left.equals(right);
418 }
419 return false;
420 }
421 public void setSearchDispatcher(SearchDispatcher searchDispatcher) {
422 this.searchDispatcher = searchDispatcher;
423 }
424
425 public SearchDispatcher getSearchDispatcher() {
426 return searchDispatcher;
427 }
428
429 }