001    /**
002     * Copyright 2005-2011 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     */
016    package org.kuali.rice.kns.web.struts.action;
017    
018    import org.apache.commons.beanutils.BeanComparator;
019    import org.apache.commons.lang.StringUtils;
020    import org.apache.struts.action.ActionForm;
021    import org.apache.struts.action.ActionForward;
022    import org.apache.struts.action.ActionMapping;
023    import org.kuali.rice.core.api.util.RiceConstants;
024    import org.kuali.rice.kns.lookup.HtmlData;
025    import org.kuali.rice.kns.lookup.LookupResultsService;
026    import org.kuali.rice.kns.lookup.LookupUtils;
027    import org.kuali.rice.kns.lookup.Lookupable;
028    import org.kuali.rice.kns.service.KNSServiceLocator;
029    import org.kuali.rice.kns.web.struts.form.MultipleValueLookupForm;
030    import org.kuali.rice.kns.web.ui.Column;
031    import org.kuali.rice.kns.web.ui.ResultRow;
032    import org.kuali.rice.krad.lookup.CollectionIncomplete;
033    import org.kuali.rice.krad.service.KRADServiceLocator;
034    import org.kuali.rice.krad.service.SequenceAccessorService;
035    import org.kuali.rice.krad.util.GlobalVariables;
036    import org.kuali.rice.krad.util.KRADConstants;
037    import org.kuali.rice.krad.util.UrlFactory;
038    
039    import javax.servlet.ServletException;
040    import javax.servlet.http.HttpServletRequest;
041    import javax.servlet.http.HttpServletResponse;
042    import java.io.IOException;
043    import java.util.ArrayList;
044    import java.util.Collection;
045    import java.util.Collections;
046    import java.util.HashMap;
047    import java.util.List;
048    import java.util.Map;
049    import java.util.Properties;
050    import java.util.Set;
051    
052    /**
053     * This class serves as the struts action for implementing multiple value lookups
054     */
055    public 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