001/**
002 * Copyright 2005-2016 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.rice.kns.web.struts.action;
017
018import org.apache.commons.beanutils.BeanComparator;
019import org.apache.commons.lang.StringUtils;
020import org.apache.struts.action.ActionForm;
021import org.apache.struts.action.ActionForward;
022import org.apache.struts.action.ActionMapping;
023import org.kuali.rice.core.api.util.RiceConstants;
024import org.kuali.rice.kns.lookup.HtmlData;
025import org.kuali.rice.kns.lookup.LookupResultsService;
026import org.kuali.rice.kns.lookup.LookupUtils;
027import org.kuali.rice.kns.lookup.Lookupable;
028import org.kuali.rice.kns.service.KNSServiceLocator;
029import org.kuali.rice.kns.web.struts.form.MultipleValueLookupForm;
030import org.kuali.rice.kns.web.ui.Column;
031import org.kuali.rice.kns.web.ui.ResultRow;
032import org.kuali.rice.krad.lookup.CollectionIncomplete;
033import org.kuali.rice.krad.service.KRADServiceLocator;
034import org.kuali.rice.krad.service.SequenceAccessorService;
035import org.kuali.rice.krad.util.GlobalVariables;
036import org.kuali.rice.krad.util.KRADConstants;
037import org.kuali.rice.krad.util.UrlFactory;
038
039import javax.servlet.ServletException;
040import javax.servlet.http.HttpServletRequest;
041import javax.servlet.http.HttpServletResponse;
042import java.io.IOException;
043import java.util.ArrayList;
044import java.util.Collection;
045import java.util.Collections;
046import java.util.HashMap;
047import java.util.List;
048import java.util.Map;
049import java.util.Properties;
050import java.util.Set;
051
052/**
053 * This class serves as the struts action for implementing multiple value lookups
054 */
055public class KualiMultipleValueLookupAction extends KualiLookupAction implements KualiTableRenderAction {
056    private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiMultipleValueLookupAction.class);
057
058    /**
059     * If there is no app param defined for the # rows/page, then this value
060     * will be used for the default
061     * 
062     * @see KualiMultipleValueLookupAction#getMaxRowsPerPage(MultipleValueLookupForm)
063     */
064    public static final int DEFAULT_MAX_ROWS_PER_PAGE = 50;
065
066
067    /**
068     * This method performs the search, and will be responsible for persisting the results via the LookupResultsService.
069     * This overrides the superclass's search action method b/c of the differences in how the results are generated and it populates
070     * certain attributes that are specific to MultipleValueLookupForm
071     * 
072     * @param mapping
073     * @param form must be an instance of MultipleValueLookupForm
074     * @param request
075     * @param response 
076     */
077    @Override
078    public ActionForward search(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
079        MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
080
081        // If this is a new search, clear out the old search results.
082        String methodToCall = findMethodToCall(form, request);
083        if (methodToCall.equalsIgnoreCase("search")) {
084            GlobalVariables.getUserSession().removeObjectsByPrefix(KRADConstants.SEARCH_METHOD);
085        }
086
087        Lookupable kualiLookupable = multipleValueLookupForm.getLookupable();
088        if (kualiLookupable == null) {
089            LOG.error("Lookupable is null.");
090            throw new RuntimeException("Lookupable is null.");
091        }
092
093        Collection displayList = new ArrayList();
094        ArrayList<ResultRow> resultTable = new ArrayList<ResultRow>();
095
096        // validate search parameters
097        kualiLookupable.validateSearchParameters(multipleValueLookupForm.getFields());
098
099        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