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