Coverage Report - org.kuali.student.common.search.service.impl.CrossSearchManager
 
Classes in this File Line Coverage Branch Coverage Complexity
CrossSearchManager
0%
0/178
0%
0/172
10.214
CrossSearchManager$1
0%
0/1
N/A
10.214
CrossSearchManager$DataType
0%
0/1
N/A
10.214
CrossSearchManager$SearchResultRowComparator
0%
0/40
0%
0/28
10.214
 
 1  
 /**
 2  
  * Copyright 2010 The Kuali Foundation Licensed under the
 3  
  * Educational Community License, Version 2.0 (the "License"); you may
 4  
  * not use this file except in compliance with the License. You may
 5  
  * obtain a copy of the License at
 6  
  *
 7  
  * http://www.osedu.org/licenses/ECL-2.0
 8  
  *
 9  
  * Unless required by applicable law or agreed to in writing,
 10  
  * software distributed under the License is distributed on an "AS IS"
 11  
  * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 12  
  * or implied. See the License for the specific language governing
 13  
  * permissions and limitations under the License.
 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.Collections;
 21  
 import java.util.Comparator;
 22  
 import java.util.Date;
 23  
 import java.util.HashMap;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 
 27  
 import org.kuali.student.common.search.dto.CrossSearchTypeInfo;
 28  
 import org.kuali.student.common.search.dto.JoinComparisonInfo;
 29  
 import org.kuali.student.common.search.dto.JoinCriteriaInfo;
 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.SortDirection;
 37  
 import org.kuali.student.common.search.dto.SubSearchInfo;
 38  
 import org.kuali.student.common.search.dto.SubSearchParamMappingInfo;
 39  
 import org.kuali.student.common.search.dto.JoinComparisonInfo.ComparisonType;
 40  
 import org.kuali.student.common.search.dto.JoinCriteriaInfo.JoinType;
 41  
 import org.kuali.student.common.search.service.SearchDispatcher;
 42  
 
 43  
 /**
 44  
  * This still needs a few things
 45  
  * 1 - no search meta(sort, pagination) is implemented
 46  
  * 2 - a way to do subselects should be implemented to reduce the processing and sheer size of the unions
 47  
  * (for example if searching for LO and the related CLU by the LO description, we need to match ALL CLUs 
 48  
  * with just the LOs that match, meaning if we had 1000 clus, and 10 LOs we would be comparing 10000 results)
 49  
  * 
 50  
  *
 51  
  */
 52  
 /**
 53  
  * @author Daniel Epstein
 54  
  *
 55  
  */
 56  0
 public class CrossSearchManager {
 57  
         private SearchDispatcher searchDispatcher;
 58  
 
 59  
         public SearchResult doCrossSearch(SearchRequest searchRequest, CrossSearchTypeInfo crossSearchType) {
 60  0
                 SearchResult searchResult = new SearchResult();
 61  
                 
 62  0
                 Map<String,SearchResult> subSearchResults = new HashMap<String,SearchResult>();
 63  
                 
 64  
                 //First perform all the subsearches
 65  0
                 for(SubSearchInfo subSearch:crossSearchType.getSubSearches()){
 66  
                         //Map the parameters to the subsearch
 67  0
                         SearchRequest subSearchRequest = new SearchRequest();
 68  
                         
 69  0
                         subSearchRequest.setSearchKey(subSearch.getSearchkey());
 70  0
                         subSearchRequest.setParams(new ArrayList<SearchParam>());
 71  
                         
 72  
                         //For each param mapping, map the paramvalue from the cross search to the sub search
 73  0
                         for(SubSearchParamMappingInfo paramMapping:subSearch.getSubSearchParamMappings()){
 74  0
                                 for(SearchParam crossSearchParam:searchRequest.getParams()){
 75  0
                                         if(paramMapping.getCrossSearchParam().equals(crossSearchParam.getKey())){
 76  0
                                                 SearchParam subSearchParam = new SearchParam();
 77  0
                                                 subSearchParam.setKey(paramMapping.getSubSearchParam());
 78  0
                                                 Object paramValue = crossSearchParam.getValue();
 79  0
                                                 if(paramValue instanceof String){
 80  0
                                                         subSearchParam.setValue((String)paramValue);
 81  0
                                                 }else if(paramValue instanceof List<?>){
 82  0
                                                         subSearchParam.setValue((List<String>)paramValue);
 83  
                                                 }
 84  0
                                                 subSearchRequest.getParams().add(subSearchParam);
 85  0
                                         }
 86  
                                 }
 87  
                         }
 88  0
                         SearchResult subSearchResult = searchDispatcher.dispatchSearch(subSearchRequest);
 89  0
                         subSearchResults.put(subSearch.getKey(), subSearchResult);
 90  0
                 }
 91  
                 
 92  
                 //merge the subsearches together using the join rules
 93  0
                 if(crossSearchType.getJoinCriteria().getComparisons().isEmpty()){
 94  
                         //If the root join has no criteria then do a simple union of rows
 95  0
                         for(Map.Entry<String,SearchResult> subSearchResult:subSearchResults.entrySet()){
 96  0
                 if (null != subSearchResult.getValue()) {
 97  0
                     for(SearchResultRow row:subSearchResult.getValue().getRows()){
 98  0
                         SearchResultRow mappedResult = mapResultRow(subSearchResult.getKey(),row,crossSearchType);
 99  0
                         searchResult.getRows().add(mappedResult);
 100  0
                     }
 101  
                 }
 102  
                         }
 103  
                 }else{
 104  
                         //merge the subsearches together using the join rules (this is in o^2 time which is bad)
 105  0
                         List <Map<String,SearchResultRow>> allPermutations = unionOfAllRows(subSearchResults);
 106  
         
 107  0
                         for(Map<String,SearchResultRow> permutation:allPermutations){
 108  0
                                 if(meetsCriteria(permutation,crossSearchType,crossSearchType.getJoinCriteria())){
 109  0
                                         SearchResultRow mappedResult = mapResultRow(permutation,crossSearchType);
 110  0
                                         searchResult.getRows().add(mappedResult);
 111  0
                                 }
 112  
                         }
 113  
                 }
 114  0
                 return metaFilter(searchResult,searchRequest);
 115  
         }
 116  
         
 117  
         
 118  
         
 119  
         
 120  
         /**
 121  
          * @param searchResult
 122  
          * @param searchRequest
 123  
          * @return a sorted and paginated result
 124  
          */
 125  
         private SearchResult metaFilter(SearchResult searchResult,
 126  
                 SearchRequest searchRequest) {
 127  
                 
 128  0
                 searchResult.setTotalResults(searchResult.getRows().size());
 129  0
                 final String sortColumn = searchRequest.getSortColumn();
 130  0
                 final SortDirection sortDirection = searchRequest.getSortDirection();
 131  
                 
 132  
                 //Sort if we need to
 133  0
                 if(sortColumn!=null){
 134  0
                         Collections.sort(searchResult.getRows(), new SearchResultRowComparator(sortColumn,sortDirection));
 135  
                 }
 136  
                 
 137  
                 
 138  
                 
 139  
                 //Paginate if we need to
 140  0
                 if(searchRequest.getMaxResults()!=null){
 141  0
                         int fromIndex=0;
 142  0
                         if(searchRequest.getStartAt()!=null){
 143  0
                                 fromIndex=searchRequest.getStartAt();
 144  
                         }
 145  0
                         int toIndex = fromIndex+searchRequest.getMaxResults();
 146  0
                         SearchResult pagedResult = new SearchResult();
 147  0
                         for (int i=fromIndex; i <= toIndex; i++) {
 148  0
                                 if (!(searchResult.getRows().size() < i+1)) {
 149  0
                                         pagedResult.getRows().add(searchResult.getRows().get(i));
 150  
                                 }
 151  
                         }
 152  
                         
 153  0
                         searchResult = pagedResult;
 154  
                 }
 155  0
                 return searchResult;
 156  
         }
 157  
 
 158  
         
 159  
         /**
 160  
          * Compares two SearchResultRow rows with a given sort direction and column
 161  
          *
 162  
          */
 163  0
         private static class SearchResultRowComparator implements Comparator<SearchResultRow> {
 164  
                 private String sortColumn;
 165  
                 private SortDirection sortDirection;
 166  
                 
 167  
                 public SearchResultRowComparator(String sortColumn,
 168  
                                 SortDirection sortDirection) {
 169  0
                         super();
 170  0
                         this.sortColumn = sortColumn;
 171  0
                         this.sortDirection = sortDirection;
 172  0
                 }
 173  
                 
 174  
                 @Override
 175  
                 public int compare(SearchResultRow r1, SearchResultRow r2) {
 176  0
                         int compareResult = 0;
 177  
                         
 178  
                         //Pares out the cell values to compare
 179  0
                         String v1=null;
 180  0
                         String v2=null;
 181  0
                         for(SearchResultCell c:r1.getCells()){
 182  0
                                 if(sortColumn.equals(c.getKey())){
 183  0
                                         v1=c.getValue();
 184  0
                                         break;
 185  
                                 }
 186  
                         }
 187  0
                         for(SearchResultCell c:r2.getCells()){
 188  0
                                 if(sortColumn.equals(c.getKey())){
 189  0
                                         v2=c.getValue();
 190  0
                                         break;
 191  
                                 }
 192  
                         }
 193  
                         
 194  
                         //Compare the values wiuth the right type (SHould be done more efficiently
 195  
                         try{
 196  0
                                 Integer v1Integer = Integer.parseInt(v1);
 197  0
                                 Integer v2Integer = Integer.parseInt(v2);
 198  0
                                 compareResult = v1Integer.compareTo(v2Integer);
 199  0
                         }catch(Exception e1){
 200  0
                                 if(v1!=null&&v2!=null&&("true".equals(v1.toLowerCase())||"false".equals(v1.toLowerCase()))&&
 201  
                                    ("true".equals(v2.toLowerCase())||"false".equals(v2.toLowerCase()))){
 202  0
                                         Boolean v1Boolean = Boolean.parseBoolean(v1);
 203  0
                                         Boolean v2Boolean = Boolean.parseBoolean(v2);
 204  0
                                         compareResult = v1Boolean.compareTo(v2Boolean);
 205  0
                                 }else{
 206  
                                         try{
 207  0
                                                 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
 208  0
                                                 Date v1Date = df.parse(v1);
 209  0
                                                 Date v2Date = df.parse(v2);
 210  0
                                                 compareResult = v1Date.compareTo(v2Date);
 211  0
                                         }catch(Exception e){
 212  0
                                                 if(v1!=null && v2!=null){
 213  0
                                                         compareResult = v1.compareTo(v2);
 214  0
                                                 }else if(v2==null){
 215  0
                                                         compareResult = 0;
 216  
                                                 }else{
 217  0
                                                         compareResult = -1; 
 218  
                                                 }
 219  0
                                         }
 220  
                                 }
 221  0
                         }
 222  
                         
 223  
                         //Sort reverse if order is descending
 224  0
                         if(SortDirection.DESC.equals(sortDirection)){
 225  0
                                 return -1 * compareResult;
 226  
                         }
 227  0
                         return compareResult;
 228  
                 }
 229  
                 
 230  
         }
 231  
 
 232  
 
 233  
 
 234  
         /**
 235  
          * Maps results from multiple searches into a single result row
 236  
          *
 237  
          * @param permutation
 238  
          * @param crossSearchType
 239  
          * @return a mapped SearchResultRow
 240  
          */
 241  
         private SearchResultRow mapResultRow(
 242  
                         Map<String, SearchResultRow> permutation,
 243  
                         CrossSearchTypeInfo crossSearchType) {
 244  
                 //FIXME this is pretty inefficient to loop through everything... a map structure for the cells might be better
 245  0
                 SearchResultRow resultRow = new SearchResultRow();
 246  0
                 for(JoinResultMappingInfo resultMapping: crossSearchType.getJoinResultMappings()){
 247  0
                         for(SearchResultCell cell: permutation.get(resultMapping.getSubSearchKey()).getCells()){
 248  0
                                 if(resultMapping.getSubSearchResultParam().equals(cell.getKey())){
 249  0
                                         SearchResultCell mappedCell = new SearchResultCell();
 250  0
                                         mappedCell.setKey(resultMapping.getResultParam());
 251  0
                                         mappedCell.setValue(cell.getValue());
 252  0
                                         resultRow.getCells().add(mappedCell);
 253  0
                                         break;//FIXME breaks are bad... but there is no map in the cells
 254  
                                 }
 255  
                         }
 256  
                 }
 257  0
                 return resultRow;
 258  
                 
 259  
         }
 260  
 
 261  
         private SearchResultRow mapResultRow(
 262  
                         String subSearchKey, SearchResultRow row,
 263  
                         CrossSearchTypeInfo crossSearchType) {
 264  0
                 SearchResultRow resultRow = new SearchResultRow();
 265  
                 
 266  0
                 for(JoinResultMappingInfo resultMapping: crossSearchType.getJoinResultMappings()){
 267  0
                         if(subSearchKey.equals(resultMapping.getSubSearchKey())){
 268  0
                                 for(SearchResultCell cell: row.getCells()){
 269  0
                                         if(resultMapping.getSubSearchResultParam().equals(cell.getKey())){
 270  0
                                                 SearchResultCell mappedCell = new SearchResultCell();
 271  0
                                                 mappedCell.setKey(resultMapping.getResultParam());
 272  0
                                                 mappedCell.setValue(cell.getValue());
 273  0
                                                 resultRow.getCells().add(mappedCell);
 274  0
                                                 break;//FIXME breaks are bad... but there is no map in the cells
 275  
                                         }
 276  
                                 }
 277  
                         }
 278  
                 }
 279  0
                 return resultRow;
 280  
         }
 281  
         /**
 282  
          * Checks each comparison of the join criteria and recursively checks through nested criteria.  
 283  
          * Short circuits for false 'AND' joins and true 'OR' joins
 284  
          * @param permutation
 285  
          * @param crossSearchType
 286  
          * @param joinCriteria
 287  
          * @return whether the criteria is met
 288  
          */
 289  
         private boolean meetsCriteria(Map<String, SearchResultRow> permutation,
 290  
                         CrossSearchTypeInfo crossSearchType, JoinCriteriaInfo joinCriteria){
 291  
 
 292  0
                 JoinType joinType = joinCriteria.getJoinType();
 293  
                 
 294  
                 //Check actual comparisons
 295  0
                 for(JoinComparisonInfo comparison:joinCriteria.getComparisons()){
 296  0
                         SearchResultRow leftResultRow =  permutation.get(comparison.getLeftHandSide().getSubSearchKey());
 297  0
                         String leftResultValue = null;
 298  0
                         if(leftResultRow!=null){
 299  0
                                 for(SearchResultCell cell: leftResultRow.getCells()){
 300  0
                                         if(comparison.getLeftHandSide().getParam().equals(cell.getKey())){
 301  0
                                                 leftResultValue = cell.getValue();
 302  0
                                                 break;//FIXME breaks are bad... but there is no map in the cells
 303  
                                         }
 304  
                                 }
 305  
                         }
 306  
                         
 307  0
                         SearchResultRow rightResultRow =  permutation.get(comparison.getRightHandSide().getSubSearchKey());
 308  0
                         String rightResultValue = null;
 309  0
                         if(rightResultRow!=null){
 310  0
                                 for(SearchResultCell cell: rightResultRow.getCells()){
 311  0
                                         if(comparison.getRightHandSide().getParam().equals(cell.getKey())){
 312  0
                                                 rightResultValue = cell.getValue();
 313  0
                                                 break;//FIXME breaks are bad... but there is no map in the cells
 314  
                                         }
 315  
                                 }
 316  
                         }                        
 317  
                         
 318  
                         //Get the compare type for the 
 319  
                         //TODO get the types for the params!
 320  0
                         if(leftResultValue==null||rightResultValue==null){
 321  0
                                 int i=0;i++;
 322  
                         }
 323  0
                         if(compare(null, leftResultValue,rightResultValue,comparison.getType())){
 324  0
                                 if(JoinType.OR.equals(joinType)){
 325  0
                                         return true;
 326  
                                 }
 327  
                         }else{
 328  0
                                 if(JoinType.AND.equals(joinType)){
 329  0
                                         return false;
 330  
                                 }
 331  
                         }
 332  0
                 }
 333  
                 
 334  
                 //Check all subcriteria next
 335  0
                 for(JoinCriteriaInfo subCriteria: joinCriteria.getJoinCriteria()){
 336  0
                         if(meetsCriteria(permutation, crossSearchType, subCriteria)){
 337  0
                                 if(JoinType.OR.equals(joinType)){
 338  0
                                         return true;
 339  
                                 }
 340  
                         }else{
 341  0
                                 if(JoinType.AND.equals(joinType)){
 342  0
                                         return false;
 343  
                                 }
 344  
                         }
 345  
                 }
 346  
                 
 347  0
                 if(JoinType.AND.equals(joinType)){
 348  0
                         return true;
 349  
                 }
 350  0
                 if(JoinType.OR.equals(joinType)){
 351  0
                         return false;
 352  
                 }
 353  
                 
 354  0
                 return false;
 355  
         }
 356  
 
 357  
         /**
 358  
          * @param searchResults
 359  
          * @return a list of all possible combinations of rows
 360  
          */
 361  
         private List <Map<String,SearchResultRow>> unionOfAllRows(Map<String, SearchResult> searchResults){
 362  0
                 List <Map<String,SearchResultRow>> r = new ArrayList<Map<String,SearchResultRow>>();
 363  0
                 for(Map.Entry<String,SearchResult> x:searchResults.entrySet()){
 364  0
                         List<Map<String,SearchResultRow>> t = new ArrayList<Map<String,SearchResultRow>>();
 365  0
                         if(x.getValue()!=null&&x.getValue().getRows()!=null){
 366  0
                                 for(SearchResultRow y:x.getValue().getRows()){
 367  0
                                         for(Map<String,SearchResultRow> i:r){
 368  0
                                                 Map<String,SearchResultRow> unions =  new HashMap<String,SearchResultRow>();
 369  0
                                                 unions.putAll(i);
 370  0
                                                 unions.put(x.getKey(), y);
 371  0
                                                 t.add(unions);
 372  0
                                         }
 373  0
                                         if(r.size()==0){
 374  0
                                                 Map<String,SearchResultRow> unions  =  new HashMap<String,SearchResultRow>();
 375  0
                                                 unions.put(x.getKey(), y);
 376  0
                                                 t.add(unions);
 377  0
                                         }
 378  
                                 }
 379  
                         }
 380  0
                         r = t;
 381  0
                 }
 382  0
                 return r;
 383  
         }        
 384  
         
 385  0
         private enum DataType{STRING,INT,BOOLEAN,DATE}
 386  
         
 387  
 
 388  
 
 389  
         private boolean compare(DataType dataType, String left, String right,
 390  
                         ComparisonType type ){
 391  
                 //FIXME needs a handle to the result params data types here
 392  
                 try{
 393  0
                         Integer leftInteger = Integer.parseInt(left);
 394  0
                         Integer rightInteger = Integer.parseInt(right);
 395  0
                         return compareInt(leftInteger,rightInteger,type);
 396  0
                 }catch(Exception e){
 397  
                 }
 398  
                 try{
 399  0
                         if(("true".equals(left.toLowerCase())||"false".equals(left.toLowerCase()))&&
 400  
                            ("true".equals(right.toLowerCase())||"false".equals(right.toLowerCase()))){
 401  0
                                 Boolean leftBoolean = Boolean.parseBoolean(left);
 402  0
                                 Boolean rightBoolean = Boolean.parseBoolean(right);
 403  0
                                 return compareBoolean(leftBoolean,rightBoolean,type);
 404  
                         }
 405  0
                 }catch(Exception e){
 406  0
                 }
 407  
                 try{
 408  0
                         SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
 409  0
                         Date leftDate = df.parse(left);
 410  0
                         Date rightDate = df.parse(right);
 411  0
                         return compareDate(leftDate,rightDate,type);
 412  0
                 }catch(Exception e){
 413  
                 }
 414  0
                 return compareString(left,right,type);
 415  
 //                switch(dataType){
 416  
 //                        case BOOLEAN:
 417  
 //                                Boolean leftBoolean = new Boolean(left);
 418  
 //                                Boolean rightBoolean = new Boolean(right);
 419  
 //                                return compareBoolean(leftBoolean,rightBoolean,type);
 420  
 //                        case DATE:
 421  
 //                                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
 422  
 //                                Date leftDate = df.parse(left);
 423  
 //                                Date rightDate = df.parse(right);
 424  
 //                                return compareDate(leftDate,rightDate,type);
 425  
 //                        case INT:
 426  
 //                                Integer leftInteger = Integer.getInteger(left);
 427  
 //                                Integer rightInteger = Integer.getInteger(right);
 428  
 //                                return compareInt(leftInteger,rightInteger,type);
 429  
 //                        case STRING:
 430  
 //                                return compareString(left,right,type);
 431  
 //                }
 432  
 //                return false;
 433  
         }
 434  
         
 435  
         private boolean compareString(String left, String right, ComparisonType type) {
 436  0
                 switch(type){
 437  
                 case EQUALS:
 438  0
                         return left.equals(right);
 439  
                 case GREATERTHAN:
 440  0
                         return left.compareTo(right) > 0;
 441  
                 case GREATERTHANEQUALS:
 442  0
                         return left.compareTo(right) >= 0;
 443  
                 case LESSTHAN:
 444  0
                         return left.compareTo(right) < 0;
 445  
                 case LESSTHANEQUALS:
 446  0
                         return left.compareTo(right) <= 0;
 447  
                 case NOTEQUALS:
 448  0
                         return !left.equals(right);
 449  
                 }
 450  0
                 return false;
 451  
         }
 452  
 
 453  
         private boolean compareInt(Integer left, Integer right, ComparisonType type) {
 454  0
                 switch(type){
 455  
                 case EQUALS:
 456  0
                         return left.equals(right);
 457  
                 case GREATERTHAN:
 458  0
                         return left.compareTo(right) > 0;
 459  
                 case GREATERTHANEQUALS:
 460  0
                         return left.compareTo(right) >= 0;
 461  
                 case LESSTHAN:
 462  0
                         return left.compareTo(right) < 0;
 463  
                 case LESSTHANEQUALS:
 464  0
                         return left.compareTo(right) <= 0;
 465  
                 case NOTEQUALS:
 466  0
                         return !left.equals(right);
 467  
                 }
 468  0
                 return false;
 469  
         }
 470  
 
 471  
         private boolean compareDate(Date left, Date right, ComparisonType type) {
 472  0
                 switch(type){
 473  
                 case EQUALS:
 474  0
                         return left.equals(right);
 475  
                 case GREATERTHAN:
 476  0
                         return left.compareTo(right) > 0;
 477  
                 case GREATERTHANEQUALS:
 478  0
                         return left.compareTo(right) >= 0;
 479  
                 case LESSTHAN:
 480  0
                         return left.compareTo(right) < 0;
 481  
                 case LESSTHANEQUALS:
 482  0
                         return left.compareTo(right) <= 0;
 483  
                 case NOTEQUALS:
 484  0
                         return !left.equals(right);
 485  
                 }
 486  0
                 return false;
 487  
         }
 488  
 
 489  
         private boolean compareBoolean(Boolean left, Boolean right,
 490  
                         ComparisonType type) {
 491  0
                 switch(type){
 492  
                 case EQUALS:
 493  0
                         return left.equals(right);
 494  
                 case GREATERTHAN:
 495  0
                         return left.compareTo(right) > 0;
 496  
                 case GREATERTHANEQUALS:
 497  0
                         return left.compareTo(right) >= 0;
 498  
                 case LESSTHAN:
 499  0
                         return left.compareTo(right) < 0;
 500  
                 case LESSTHANEQUALS:
 501  0
                         return left.compareTo(right) <= 0;
 502  
                 case NOTEQUALS:
 503  0
                         return !left.equals(right);
 504  
                 }
 505  0
                 return false;
 506  
         }
 507  
         public void setSearchDispatcher(SearchDispatcher searchDispatcher) {
 508  0
                 this.searchDispatcher = searchDispatcher;
 509  0
         }
 510  
 
 511  
 
 512  
 }