View Javadoc
1   /**
2    * Copyright 2005-2015 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kns.web.struts.action;
17  
18  import org.apache.commons.beanutils.BeanComparator;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.struts.action.ActionForm;
21  import org.apache.struts.action.ActionForward;
22  import org.apache.struts.action.ActionMapping;
23  import org.kuali.rice.core.api.util.RiceConstants;
24  import org.kuali.rice.kns.lookup.HtmlData;
25  import org.kuali.rice.kns.lookup.LookupResultsService;
26  import org.kuali.rice.kns.lookup.LookupUtils;
27  import org.kuali.rice.kns.lookup.Lookupable;
28  import org.kuali.rice.kns.service.KNSServiceLocator;
29  import org.kuali.rice.kns.web.struts.form.MultipleValueLookupForm;
30  import org.kuali.rice.kns.web.ui.Column;
31  import org.kuali.rice.kns.web.ui.ResultRow;
32  import org.kuali.rice.krad.lookup.CollectionIncomplete;
33  import org.kuali.rice.krad.service.KRADServiceLocator;
34  import org.kuali.rice.krad.service.SequenceAccessorService;
35  import org.kuali.rice.krad.util.GlobalVariables;
36  import org.kuali.rice.krad.util.KRADConstants;
37  import org.kuali.rice.krad.util.UrlFactory;
38  
39  import javax.servlet.ServletException;
40  import javax.servlet.http.HttpServletRequest;
41  import javax.servlet.http.HttpServletResponse;
42  import java.io.IOException;
43  import java.util.ArrayList;
44  import java.util.Collection;
45  import java.util.Collections;
46  import java.util.HashMap;
47  import java.util.List;
48  import java.util.Map;
49  import java.util.Properties;
50  import java.util.Set;
51  
52  /**
53   * This class serves as the struts action for implementing multiple value lookups
54   */
55  public class KualiMultipleValueLookupAction extends KualiLookupAction implements KualiTableRenderAction {
56      private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiMultipleValueLookupAction.class);
57  
58      /**
59       * If there is no app param defined for the # rows/page, then this value
60       * will be used for the default
61       * 
62       * @see KualiMultipleValueLookupAction#getMaxRowsPerPage(MultipleValueLookupForm)
63       */
64      public static final int DEFAULT_MAX_ROWS_PER_PAGE = 50;
65  
66  
67      /**
68       * This method performs the search, and will be responsible for persisting the results via the LookupResultsService.
69       * This overrides the superclass's search action method b/c of the differences in how the results are generated and it populates
70       * certain attributes that are specific to MultipleValueLookupForm
71       * 
72       * @param mapping
73       * @param form must be an instance of MultipleValueLookupForm
74       * @param request
75       * @param response 
76       */
77      @Override
78      public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
79          MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
80  
81          // If this is a new search, clear out the old search results.
82          String methodToCall = findMethodToCall(form, request);
83          if (methodToCall.equalsIgnoreCase("search")) {
84              GlobalVariables.getUserSession().removeObjectsByPrefix(KRADConstants.SEARCH_METHOD);
85          }
86  
87          Lookupable kualiLookupable = multipleValueLookupForm.getLookupable();
88          if (kualiLookupable == null) {
89              LOG.error("Lookupable is null.");
90              throw new RuntimeException("Lookupable is null.");
91          }
92  
93          Collection displayList = new ArrayList();
94          ArrayList<ResultRow> resultTable = new ArrayList<ResultRow>();
95  
96          // validate search parameters
97          kualiLookupable.validateSearchParameters(multipleValueLookupForm.getFields());
98  
99          boolean bounded = true;
100 
101         displayList = performMultipleValueLookup(multipleValueLookupForm, resultTable, getMaxRowsPerPage(multipleValueLookupForm), bounded);
102         if (kualiLookupable.isSearchUsingOnlyPrimaryKeyValues()) {
103             multipleValueLookupForm.setSearchUsingOnlyPrimaryKeyValues(true);
104             multipleValueLookupForm.setPrimaryKeyFieldLabels(kualiLookupable.getPrimaryKeyFieldLabels());
105         }
106         else {
107             multipleValueLookupForm.setSearchUsingOnlyPrimaryKeyValues(false);
108             multipleValueLookupForm.setPrimaryKeyFieldLabels(KRADConstants.EMPTY_STRING);
109         }
110 
111         //request.setAttribute("reqSearchResultsActualSize", ((CollectionIncomplete) displayList).getActualSizeIfTruncated());
112 
113         if ( displayList instanceof CollectionIncomplete ){
114             request.setAttribute("reqSearchResultsActualSize", ((CollectionIncomplete) displayList).getActualSizeIfTruncated());
115         } else {
116             request.setAttribute("reqSearchResultsActualSize", displayList.size() );
117         }
118 
119         request.setAttribute("reqSearchResults", resultTable);
120 
121         //multipleValueLookupForm.setResultsActualSize((int) ((CollectionIncomplete) displayList).getActualSizeIfTruncated().longValue());
122 
123         if ( displayList instanceof CollectionIncomplete ){
124             multipleValueLookupForm.setResultsActualSize((int) ((CollectionIncomplete) displayList).getActualSizeIfTruncated().longValue());
125         } else {
126             multipleValueLookupForm.setResultsActualSize(displayList.size());
127         }
128 
129 
130         multipleValueLookupForm.setResultsLimitedSize(resultTable.size());
131 
132         if (request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY) != null) {
133             GlobalVariables.getUserSession().removeObject(request.getParameter(KRADConstants.SEARCH_LIST_REQUEST_KEY));
134         }
135         request.setAttribute(KRADConstants.SEARCH_LIST_REQUEST_KEY, GlobalVariables.getUserSession().addObjectWithGeneratedKey(resultTable, KRADConstants.SEARCH_LIST_KEY_PREFIX));
136 
137         request.getParameter(KRADConstants.REFRESH_CALLER);
138 
139         return mapping.findForward(RiceConstants.MAPPING_BASIC);
140     }
141 
142     /**
143      * This method switches to another page on a multi-value lookup
144      * 
145      * @param mapping
146      * @param form must be an instance of MultipleValueLookupForm
147      * @param request
148      * @param response
149      * @return
150      * @throws Exception
151      */
152     @Override
153     public ActionForward switchToPage(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
154         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
155         List<ResultRow> resultTable = switchToPage(multipleValueLookupForm, getMaxRowsPerPage(multipleValueLookupForm));
156         request.setAttribute("reqSearchResults", resultTable);
157         return mapping.findForward(RiceConstants.MAPPING_BASIC);
158     }
159 
160     /**
161      * This method sorts a column.  If the page is currently sorted on a certain column,
162      * and the same column is selected to be sorted again, then the results will be 
163      * reversed.  After the search method is called, it is difficult to determine the sort
164      * order of the result table, so no column is considered sorted.  So, after a search, we were
165      * to click sort on an already sorted column, it would appear to have no effect.  Subsequent clicks
166      * would tell you  
167      * 
168      * @param mapping
169      * @param form must be an instance of MultipleValueLookupForm
170      * @param request
171      * @param response
172      * @return
173      * @throws Exception
174      */
175     @Override
176     public ActionForward sort(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
177         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
178         List<ResultRow> resultTable = sort(multipleValueLookupForm, getMaxRowsPerPage(multipleValueLookupForm));
179         request.setAttribute("reqSearchResults", resultTable);
180         return mapping.findForward(RiceConstants.MAPPING_BASIC);
181     }
182 
183     /**
184      * This method does the processing necessary to return selected results and sends a redirect back to the lookup caller
185      * 
186      * @param mapping
187      * @param form must be an instance of MultipleValueLookupForm
188      * @param request
189      * @param response
190      * @return
191      * @throws Exception
192      */
193     public ActionForward prepareToReturnSelectedResults(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
194         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
195         if (StringUtils.isBlank(multipleValueLookupForm.getLookupResultsSequenceNumber())) {
196             // no search was executed
197             return prepareToReturnNone(mapping, form, request, response);
198         }
199 
200         prepareToReturnSelectedResultBOs(multipleValueLookupForm);
201 
202         // build the parameters for the refresh url
203         Properties parameters = new Properties();
204         parameters.put(KRADConstants.LOOKUP_RESULTS_BO_CLASS_NAME, multipleValueLookupForm.getBusinessObjectClassName());
205         parameters.put(KRADConstants.LOOKUP_RESULTS_SEQUENCE_NUMBER, multipleValueLookupForm.getLookupResultsSequenceNumber());
206         parameters.put(KRADConstants.DOC_FORM_KEY, multipleValueLookupForm.getFormKey());
207         parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.RETURN_METHOD_TO_CALL);
208         parameters.put(KRADConstants.REFRESH_CALLER, KRADConstants.MULTIPLE_VALUE);
209         parameters.put(KRADConstants.ANCHOR, multipleValueLookupForm.getLookupAnchor());
210         parameters.put(KRADConstants.LOOKED_UP_COLLECTION_NAME, multipleValueLookupForm.getLookedUpCollectionName());
211         if(multipleValueLookupForm.getDocNum() != null){
212             parameters.put(KRADConstants.DOC_NUM, multipleValueLookupForm.getDocNum());
213         }
214 
215 
216         String backUrl = UrlFactory.parameterizeUrl(multipleValueLookupForm.getBackLocation(), parameters);
217         return new ActionForward(backUrl, true);
218     }
219 
220     /**
221      * This method selects all results across all pages
222      * @param mapping
223      * @param form must be an instance of MultipleValueLookupForm
224      * @param request
225      * @param response
226      * @return
227      * @throws Exception
228      */
229     public ActionForward selectAll(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
230         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
231         List<ResultRow> resultTable = selectAll(multipleValueLookupForm, getMaxRowsPerPage(multipleValueLookupForm));
232         request.setAttribute("reqSearchResults", resultTable);
233         return mapping.findForward(RiceConstants.MAPPING_BASIC);
234     }
235 
236     /**
237      * This method unselects all results across all pages
238      * 
239      * @param mapping
240      * @param form must be an instance of MultipleValueLookupForm
241      * @param request
242      * @param response
243      * @return
244      * @throws Exception
245      */
246     public ActionForward unselectAll(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
247         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
248         List<ResultRow> resultTable = unselectAll(multipleValueLookupForm, getMaxRowsPerPage(multipleValueLookupForm));
249         request.setAttribute("reqSearchResults", resultTable);
250         return mapping.findForward(RiceConstants.MAPPING_BASIC);
251     }
252 
253     /**
254      * This method overrides the super class cancel method because it is basically equivalent to clicking prepare to return none 
255      * 
256      * @see KualiLookupAction#cancel(org.apache.struts.action.ActionMapping, org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
257      */
258     @Override
259     public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
260         return prepareToReturnNone(mapping, form, request, response);
261     }
262 
263 
264     /**
265      * This method returns none of the selected results and redirects back to the lookup caller.
266      * @param mapping
267      * @param form must be an instance of MultipleValueLookupForm
268      * @param request
269      * @param response
270      * @return
271      * @throws Exception
272      */
273     public ActionForward prepareToReturnNone(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
274         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
275         prepareToReturnNone(multipleValueLookupForm);
276 
277         // build the parameters for the refresh url
278         Properties parameters = new Properties();
279         parameters.put(KRADConstants.DOC_FORM_KEY, multipleValueLookupForm.getFormKey());
280         parameters.put(KRADConstants.DISPATCH_REQUEST_PARAMETER, KRADConstants.RETURN_METHOD_TO_CALL);
281         parameters.put(KRADConstants.REFRESH_CALLER, KRADConstants.MULTIPLE_VALUE);
282         parameters.put(KRADConstants.ANCHOR, multipleValueLookupForm.getLookupAnchor());
283         if(multipleValueLookupForm.getDocNum() != null){
284             parameters.put(KRADConstants.DOC_NUM, multipleValueLookupForm.getDocNum());
285         }
286         String backUrl = UrlFactory.parameterizeUrl(multipleValueLookupForm.getBackLocation(), parameters);
287         return new ActionForward(backUrl, true);
288     }
289 
290     /**
291      * This method prepares to export results.  Note: this method will not look for any rows selected since the last page view, so it is best
292      * that exporting opens in a new browser window.
293      * 
294      * @param mapping
295      * @param form must be an instance of MultipleValueLookupForm
296      * @param request
297      * @param response
298      * @return
299      * @throws Exception
300      */
301     public ActionForward export(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
302         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
303         List<ResultRow> resultTable = prepareToExport(multipleValueLookupForm);
304         request.setAttribute("reqSearchResults", resultTable);
305         return mapping.findForward(RiceConstants.MAPPING_BASIC);
306     }
307 
308     /**
309      * This method performs the lookup and returns a collection of lookup items.  Also initializes values in the form
310      * that will allow the multiple value lookup page to render
311      * 
312      * @param multipleValueLookupForm
313      * @param resultTable a list of result rows (used to generate what's shown in the UI).  This list will be modified by this method
314      * @param maxRowsPerPage
315      * @param bounded whether the results will be bounded
316      * @return the list of result BOs, possibly bounded by size
317      */
318     protected Collection performMultipleValueLookup(MultipleValueLookupForm multipleValueLookupForm, List<ResultRow> resultTable, int maxRowsPerPage, boolean bounded) {
319         Lookupable lookupable = multipleValueLookupForm.getLookupable();
320         Collection displayList = lookupable.performLookup(multipleValueLookupForm, resultTable, bounded);
321 
322         List defaultSortColumns = lookupable.getDefaultSortColumns();
323         if (defaultSortColumns != null && !defaultSortColumns.isEmpty() && resultTable != null && !resultTable.isEmpty()) {
324             // there's a default sort order, just find the first sort column, and we can't go wrong
325             String firstSortColumn = (String) defaultSortColumns.get(0);
326 
327             // go thru the first result row to find the index of the column (more efficient than calling lookupable.getColumns since we don't have to recreate column list)
328             int firstSortColumnIdx = -1;
329             List<Column> columnsForFirstResultRow = resultTable.get(0).getColumns();
330             for (int i = 0; i < columnsForFirstResultRow.size(); i++) {
331                 if (StringUtils.equals(firstSortColumn, columnsForFirstResultRow.get(i).getPropertyName())) {
332                     firstSortColumnIdx = i;
333                     break;
334                 }
335             }
336             multipleValueLookupForm.setColumnToSortIndex(firstSortColumnIdx);
337         }
338         else {
339             // don't know how results were sorted, so we just say -1
340             multipleValueLookupForm.setColumnToSortIndex(-1);
341         }
342 
343         // we just performed the lookup, so we're on the first page (indexed from 0)
344         multipleValueLookupForm.jumpToFirstPage(resultTable.size(), maxRowsPerPage);
345 
346         SequenceAccessorService sas = KRADServiceLocator.getSequenceAccessorService();
347         Long nextSeq = sas.getNextAvailableSequenceNumber(KRADConstants.LOOKUP_RESULTS_SEQUENCE);
348         String lookupResultsSequenceNumber = nextSeq.toString();
349         multipleValueLookupForm.setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
350         try {
351             LookupResultsService lookupResultsService = KNSServiceLocator.getLookupResultsService();
352             lookupResultsService.persistResultsTable(lookupResultsSequenceNumber, resultTable,
353                     GlobalVariables.getUserSession().getPerson().getPrincipalId());
354         }
355         catch (Exception e) {
356             LOG.error("error occured trying to persist multiple lookup results", e);
357             throw new RuntimeException("error occured trying to persist multiple lookup results");
358         }
359 
360         // since new search, nothing's checked
361         multipleValueLookupForm.setCompositeObjectIdMap(new HashMap<String, String>());
362 
363         return displayList;
364     }
365 
366     /**
367      * This method performs the operations necessary for a multiple value lookup to switch to another page of results and rerender the page
368      * @param multipleValueLookupForm
369      * @param maxRowsPerPage
370      * @return a list of result rows, used by the UI to render the page
371      */
372     protected List<ResultRow> switchToPage(MultipleValueLookupForm multipleValueLookupForm, int maxRowsPerPage) {
373         String lookupResultsSequenceNumber = multipleValueLookupForm.getLookupResultsSequenceNumber();
374 
375         List<ResultRow> resultTable = null;
376         try {
377             resultTable = KNSServiceLocator.getLookupResultsService().retrieveResultsTable(lookupResultsSequenceNumber, GlobalVariables.getUserSession().getPerson().getPrincipalId());
378         }
379         catch (Exception e) {
380             LOG.error("error occured trying to retrieve multiple lookup results", e);
381             throw new RuntimeException("error occured trying to retrieve multiple lookup results");
382         }
383 
384         multipleValueLookupForm.jumpToPage(multipleValueLookupForm.getSwitchToPageNumber(), resultTable.size(), maxRowsPerPage);
385 
386         multipleValueLookupForm.setColumnToSortIndex(Integer.parseInt(multipleValueLookupForm.getPreviouslySortedColumnIndex()));
387         multipleValueLookupForm.setCompositeObjectIdMap(LookupUtils.generateCompositeSelectedObjectIds(multipleValueLookupForm.getPreviouslySelectedObjectIdSet(),
388                 multipleValueLookupForm.getDisplayedObjectIdSet(), multipleValueLookupForm.getSelectedObjectIdSet()));
389         return resultTable;
390     }
391 
392     /**
393      * This method performs the operations necessary for a multiple value lookup to sort results and rerender the page
394      * 
395      * @param multipleValueLookupForm
396      * @param maxRowsPerPage
397      * @return a list of result rows, used by the UI to render the page
398      */
399     protected List<ResultRow> sort(MultipleValueLookupForm multipleValueLookupForm, int maxRowsPerPage) {
400         String lookupResultsSequenceNumber = multipleValueLookupForm.getLookupResultsSequenceNumber();
401 
402         LookupResultsService lookupResultsService = KNSServiceLocator.getLookupResultsService();
403 
404         List<ResultRow> resultTable = null;
405         try {
406             resultTable = lookupResultsService.retrieveResultsTable(lookupResultsSequenceNumber, GlobalVariables.getUserSession().getPerson().getPrincipalId());
407         }
408         catch (Exception e) {
409             LOG.error("error occured trying to retrieve multiple lookup results", e);
410             throw new RuntimeException("error occured trying to retrieve multiple lookup results");
411         }
412 
413         int columnToSortOn = multipleValueLookupForm.getColumnToSortIndex();
414         int columnCurrentlySortedOn = Integer.parseInt(multipleValueLookupForm.getPreviouslySortedColumnIndex());
415 
416         // if columnCurrentlySortedOn is -1, that means that we don't know which column we were originally sorting on
417         // after a search, it's hard to tell which of the columns we're sorted on,
418 
419         if (columnToSortOn == columnCurrentlySortedOn) {
420             // we're already sorted on the same column that the user clicked on, so we reverse the list
421             Collections.reverse(resultTable);
422         }
423         else {
424             // sorting on a different column, so we have to sort
425 
426             // HACK ALERT for findBestValueComparatorForColumn, since there's no central place to know
427             // which comparator we should use to compare values in a column
428             Collections.sort(resultTable, new BeanComparator("columns[" + columnToSortOn + "].propertyValue", LookupUtils.findBestValueComparatorForColumn(resultTable, columnToSortOn)));
429         }
430 
431         // repersist the list
432         try {
433             lookupResultsService.persistResultsTable(lookupResultsSequenceNumber, resultTable, 
434                     GlobalVariables.getUserSession().getPerson().getPrincipalId());
435         }
436         catch (Exception e) {
437             LOG.error("error occured trying to persist multiple lookup results", e);
438             throw new RuntimeException("error occured trying to persist multiple lookup results");
439         }
440 
441         // we just performed the sort, so go back to first page
442         multipleValueLookupForm.jumpToFirstPage(resultTable.size(), maxRowsPerPage);
443 
444         multipleValueLookupForm.setCompositeObjectIdMap(LookupUtils.generateCompositeSelectedObjectIds(multipleValueLookupForm.getPreviouslySelectedObjectIdSet(),
445                 multipleValueLookupForm.getDisplayedObjectIdSet(), multipleValueLookupForm.getSelectedObjectIdSet()));
446         return resultTable;
447     }
448 
449     /**
450      * This method performs the operations necessary for a multiple value lookup keep track of which results have been selected to be returned
451      * to the calling document.  Note, this method does not actually requery for the results.
452      * 
453      * @param multipleValueLookupForm
454      */
455     protected void prepareToReturnSelectedResultBOs(MultipleValueLookupForm multipleValueLookupForm) {
456         String lookupResultsSequenceNumber = multipleValueLookupForm.getLookupResultsSequenceNumber();
457         if (StringUtils.isBlank(lookupResultsSequenceNumber)) {
458             // pressed return before searching
459             return;
460         }
461         Map<String, String> compositeObjectIdMap = LookupUtils.generateCompositeSelectedObjectIds(multipleValueLookupForm.getPreviouslySelectedObjectIdSet(),
462                 multipleValueLookupForm.getDisplayedObjectIdSet(), multipleValueLookupForm.getSelectedObjectIdSet());
463         Set<String> compositeObjectIds = compositeObjectIdMap.keySet();
464         try {
465             LookupResultsService lookupResultsService = KNSServiceLocator.getLookupResultsService();
466             lookupResultsService.persistSelectedObjectIds(lookupResultsSequenceNumber, compositeObjectIds,
467                     GlobalVariables.getUserSession().getPerson().getPrincipalId());
468         }
469         catch (Exception e) {
470             LOG.error("error occured trying to retrieve selected multiple lookup results", e);
471             throw new RuntimeException("error occured trying to retrieve selected multiple lookup results");
472         }
473     }
474 
475     /**
476      * This method performs the operations necessary for a multiple value lookup to return no results to the calling page
477      * 
478      * @param multipleValueLookupForm
479      */
480     protected void prepareToReturnNone(MultipleValueLookupForm multipleValueLookupForm) {
481         String lookupResultsSequenceNumber = multipleValueLookupForm.getLookupResultsSequenceNumber();
482         try {
483             if (StringUtils.isNotBlank(lookupResultsSequenceNumber)) {
484                 // we're returning nothing, so we try to get rid of stuff
485                 LookupResultsService lookupResultsService = KNSServiceLocator.getLookupResultsService();
486                 lookupResultsService.clearPersistedLookupResults(lookupResultsSequenceNumber);
487                 multipleValueLookupForm.setLookupResultsSequenceNumber(null);
488             }
489         }
490         catch (Exception e) {
491             // not a big deal, continue on and purge w/ a batch job
492             LOG.error("error occured trying to clear lookup results seq nbr " + lookupResultsSequenceNumber, e);
493         }
494     }
495 
496     /**
497      * This method performs the operations necessary for a multiple value lookup to export the rows via display tag
498      * 
499      * Note: this method assumes that the export will be opened in a new browser window, therefore, persisting the selected
500      * checkboxes will not be needed.
501      * 
502      * @param multipleValueLookupForm
503      * @return a list of result rows, to be used by display tag to render the results
504      */
505     protected List<ResultRow> prepareToExport(MultipleValueLookupForm multipleValueLookupForm) {
506         String lookupResultsSequenceNumber = multipleValueLookupForm.getLookupResultsSequenceNumber();
507 
508         List<ResultRow> resultTable = null;
509         try {
510             LookupResultsService lookupResultsService = KNSServiceLocator.getLookupResultsService();
511             resultTable = lookupResultsService.retrieveResultsTable(lookupResultsSequenceNumber, GlobalVariables.getUserSession().getPerson().getPrincipalId());
512         }
513         catch (Exception e) {
514             LOG.error("error occured trying to export multiple lookup results", e);
515             throw new RuntimeException("error occured trying to export multiple lookup results");
516         }
517         return resultTable;
518     }
519 
520 
521     /**
522      * This method performs the operations necessary for a multiple value lookup to select all of the results and rerender the page
523      * @param multipleValueLookupForm
524      * @param maxRowsPerPage
525      * @return a list of result rows, used by the UI to render the page
526      */
527     protected List<ResultRow> selectAll(MultipleValueLookupForm multipleValueLookupForm, int maxRowsPerPage) {
528         String lookupResultsSequenceNumber = multipleValueLookupForm.getLookupResultsSequenceNumber();
529 
530         List<ResultRow> resultTable = null;
531         try {
532             LookupResultsService lookupResultsService = KNSServiceLocator.getLookupResultsService();
533             resultTable = lookupResultsService.retrieveResultsTable(lookupResultsSequenceNumber, GlobalVariables.getUserSession().getPerson().getPrincipalId());
534         }
535         catch (Exception e) {
536             LOG.error("error occured trying to export multiple lookup results", e);
537             throw new RuntimeException("error occured trying to export multiple lookup results");
538         }
539 
540         Map<String, String> selectedObjectIds = new HashMap<String, String>();
541         for (ResultRow row : resultTable) {
542             String objId = row.getObjectId();
543             HtmlData.InputHtmlData returnUrl = (HtmlData.InputHtmlData) row.getReturnUrlHtmlData();
544             returnUrl.setChecked(HtmlData.InputHtmlData.CHECKBOX_CHECKED_VALUE);
545             row.setReturnUrl(returnUrl.constructCompleteHtmlTag());
546             if(objId != null){
547                 selectedObjectIds.put(objId, objId);
548             }
549         }
550 
551         multipleValueLookupForm.jumpToPage(multipleValueLookupForm.getViewedPageNumber(), resultTable.size(), maxRowsPerPage);
552         multipleValueLookupForm.setColumnToSortIndex(Integer.parseInt(multipleValueLookupForm.getPreviouslySortedColumnIndex()));
553         multipleValueLookupForm.setCompositeObjectIdMap(selectedObjectIds);
554 
555         return resultTable;
556     }
557 
558     @Override
559     public ActionForward clearValues(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
560         MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
561 
562         // call the following methods to clear the persisted results
563         prepareToReturnNone(multipleValueLookupForm);
564 
565         return super.clearValues(mapping, form, request, response);
566     }
567 
568     /**
569      * This method performs the operations necessary for a multiple value lookup to unselect all of the results and rerender the page
570      * @param multipleValueLookupForm
571      * @param maxRowsPerPage
572      * @return a list of result rows, used by the UI to render the page
573      */
574     protected List<ResultRow> unselectAll(MultipleValueLookupForm multipleValueLookupForm, int maxRowsPerPage) {
575         String lookupResultsSequenceNumber = multipleValueLookupForm.getLookupResultsSequenceNumber();
576 
577         List<ResultRow> resultTable = null;
578         try {
579             LookupResultsService lookupResultsService = KNSServiceLocator.getLookupResultsService();
580             resultTable = lookupResultsService.retrieveResultsTable(lookupResultsSequenceNumber, GlobalVariables.getUserSession().getPerson().getPrincipalId());
581         }
582         catch (Exception e) {
583             LOG.error("error occured trying to export multiple lookup results", e);
584             throw new RuntimeException("error occured trying to export multiple lookup results");
585         }
586 
587         Map<String, String> selectedObjectIds = new HashMap<String, String>();
588         // keep map empty since we're not selecting anything
589 
590         multipleValueLookupForm.jumpToPage(multipleValueLookupForm.getViewedPageNumber(), resultTable.size(), maxRowsPerPage);
591         multipleValueLookupForm.setColumnToSortIndex(Integer.parseInt(multipleValueLookupForm.getPreviouslySortedColumnIndex()));
592         multipleValueLookupForm.setCompositeObjectIdMap(selectedObjectIds);
593 
594         return resultTable;
595     }
596 
597     /**
598      * This method computes the max number of rows that should be rendered per page for a multiple value lookup.
599      * 
600      * This method first looks for an application parameter in FS_PARM_T, group SYSTEM, multipleValueLookupResultsPerPage
601      * 
602      * if someone wants to implement something where a user can decide how many results to display per page, 
603      * this method is the place to do it.  Make this method read form values to determine the max rows per page based on the user inputs
604      * 
605      * @see org.kuali.rice.krad.util.KRADConstants.SystemGroupParameterNames#MULTIPLE_VALUE_LOOKUP_RESULTS_PER_PAGE
606      * @see #DEFAULT_MAX_ROWS_PER_PAGE
607      * @param multipleValueLookupForm the form
608      * @return
609      */
610     protected int getMaxRowsPerPage(MultipleValueLookupForm multipleValueLookupForm) {
611         Integer appMaxRowsPerPage = LookupUtils.getApplicationMaximumSearchResulsPerPageForMultipleValueLookups();
612         if (appMaxRowsPerPage == null) {
613             LOG.warn("Couldn't find application results per page for MV lookups.  Using default of " + DEFAULT_MAX_ROWS_PER_PAGE);
614             appMaxRowsPerPage = new Integer(DEFAULT_MAX_ROWS_PER_PAGE);
615         }
616         return appMaxRowsPerPage;
617     }
618 }
619