001: /*
002: * Copyright 2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.module.gl.web.struts.action;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.List;
022: import java.util.Properties;
023:
024: import javax.servlet.http.HttpServletRequest;
025: import javax.servlet.http.HttpServletResponse;
026:
027: import org.apache.commons.lang.StringUtils;
028: import org.apache.struts.action.ActionForm;
029: import org.apache.struts.action.ActionForward;
030: import org.apache.struts.action.ActionMapping;
031: import org.kuali.core.lookup.CollectionIncomplete;
032: import org.kuali.core.lookup.LookupResultsService;
033: import org.kuali.core.lookup.Lookupable;
034: import org.kuali.core.service.KualiConfigurationService;
035: import org.kuali.core.service.SequenceAccessorService;
036: import org.kuali.core.util.GlobalVariables;
037: import org.kuali.core.util.UrlFactory;
038: import org.kuali.core.web.struts.action.KualiMultipleValueLookupAction;
039: import org.kuali.core.web.struts.form.MultipleValueLookupForm;
040: import org.kuali.core.web.ui.Column;
041: import org.kuali.core.web.ui.ResultRow;
042: import org.kuali.kfs.KFSConstants;
043: import org.kuali.kfs.KFSKeyConstants;
044: import org.kuali.kfs.KFSPropertyConstants;
045: import org.kuali.kfs.context.SpringContext;
046: import org.kuali.module.gl.GLConstants;
047: import org.kuali.module.gl.bo.AccountBalance;
048: import org.kuali.module.gl.util.ObjectHelper;
049: import org.kuali.module.gl.web.lookupable.AccountBalanceByConsolidationLookupableHelperServiceImpl;
050: import org.kuali.module.gl.web.struts.form.BalanceInquiryLookupForm;
051:
052: /**
053: * Balance inquiries are pretty much just lookups already, but are not used in the traditional sense. In most cases, balance
054: * inquiries only show the end-user data, and allow the end-user to drill-down into inquiries. A traditional lookup allows the user
055: * to return data to a form. This class is for balance inquiries implemented in the sense of a traditional lookup for forms that
056: * pull data out of inquiries.<br/> <br/> One example of this is the
057: * <code>{@link org.kuali.module.labor.document.SalaryExpenseTransferDocument}</code> which creates source lines from a labor
058: * ledger balance inquiry screen.<br/> <br/> This is a <code>{@link KualiMultipleValueLookupAction}</code> which required some
059: * customization because requirements were not possible with displaytag.
060: *
061: * @see org.kuali.module.labor.document.SalaryExpenseTransferDocument
062: * @see org.kuali.module.labor.web.struts.action.SalaryExpenseTransferAction;
063: * @see org.kuali.module.labor.web.struts.form.SalaryExpenseTransferForm;
064: */
065: public class BalanceInquiryLookupAction extends
066: KualiMultipleValueLookupAction {
067: private static final org.apache.commons.logging.Log LOG = org.apache.commons.logging.LogFactory
068: .getLog(BalanceInquiryLookupAction.class);
069:
070: private static final String TOTALS_TABLE_KEY = "totalsTable";
071:
072: /**
073: * If there is no app param defined for the # rows/page, then this value will be used for the default
074: *
075: * @see KualiMultipleValueLookupAction#getMaxRowsPerPage(MultipleValueLookupForm)
076: */
077: public static final int DEFAULT_MAX_ROWS_PER_PAGE = 50;
078:
079: private KualiConfigurationService kualiConfigurationService;
080: private String[] totalTitles;
081:
082: public BalanceInquiryLookupAction() {
083: super ();
084: kualiConfigurationService = SpringContext
085: .getBean(KualiConfigurationService.class);
086: }
087:
088: private void setTotalTitles() {
089: totalTitles = new String[7];
090:
091: totalTitles[0] = kualiConfigurationService
092: .getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME);
093: totalTitles[1] = kualiConfigurationService
094: .getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME_FROM_TRANSFERS);
095: totalTitles[2] = kualiConfigurationService
096: .getPropertyString(KFSKeyConstants.AccountBalanceService.INCOME_TOTAL);
097: totalTitles[3] = kualiConfigurationService
098: .getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE);
099: totalTitles[4] = kualiConfigurationService
100: .getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE_FROM_TRANSFERS);
101: totalTitles[5] = kualiConfigurationService
102: .getPropertyString(KFSKeyConstants.AccountBalanceService.EXPENSE_TOTAL);
103: totalTitles[6] = kualiConfigurationService
104: .getPropertyString(KFSKeyConstants.AccountBalanceService.TOTAL);
105:
106: }
107:
108: private String[] getTotalTitles() {
109: if (null == totalTitles) {
110: setTotalTitles();
111: }
112:
113: return totalTitles;
114: }
115:
116: /**
117: * search - sets the values of the data entered on the form on the jsp into a map and then searches for the results.
118: */
119: public ActionForward search(ActionMapping mapping, ActionForm form,
120: HttpServletRequest request, HttpServletResponse response)
121: throws Exception {
122: BalanceInquiryLookupForm lookupForm = (BalanceInquiryLookupForm) form;
123: Lookupable lookupable = lookupForm.getLookupable();
124:
125: if (lookupable == null) {
126: LOG.error("Lookupable is null.");
127: throw new RuntimeException("Lookupable is null.");
128: }
129:
130: Collection displayList = new ArrayList();
131: CollectionIncomplete incompleteDisplayList;
132: List<ResultRow> resultTable = new ArrayList<ResultRow>();
133: Long totalSize;
134: boolean bounded = true;
135:
136: lookupable.validateSearchParameters(lookupForm.getFields());
137:
138: displayList = performMultipleValueLookup(lookupForm,
139: resultTable, getMaxRowsPerPage(lookupForm), bounded);
140: incompleteDisplayList = (CollectionIncomplete) displayList;
141: totalSize = incompleteDisplayList.getActualSizeIfTruncated();
142:
143: if (lookupable.isSearchUsingOnlyPrimaryKeyValues()) {
144: lookupForm.setSearchUsingOnlyPrimaryKeyValues(true);
145: lookupForm.setPrimaryKeyFieldLabels(lookupable
146: .getPrimaryKeyFieldLabels());
147: } else {
148: lookupForm.setSearchUsingOnlyPrimaryKeyValues(false);
149: lookupForm
150: .setPrimaryKeyFieldLabels(KFSConstants.EMPTY_STRING);
151: }
152:
153: // TODO: use inheritance instead of this if statement
154: if (lookupable.getLookupableHelperService() instanceof AccountBalanceByConsolidationLookupableHelperServiceImpl) {
155: Object[] resultTableAsArray = resultTable.toArray();
156: Collection totalsTable = new ArrayList();
157:
158: int arrayIndex = 0;
159:
160: try {
161: for (int listIndex = 0; listIndex < incompleteDisplayList
162: .size(); listIndex++) {
163: AccountBalance balance = (AccountBalance) incompleteDisplayList
164: .get(listIndex);
165: boolean ok = ObjectHelper.isOneOf(balance
166: .getTitle(), getTotalTitles());
167: if (ok) {
168: if (totalSize > 7) {
169: totalsTable
170: .add(resultTableAsArray[arrayIndex]);
171: }
172: resultTable
173: .remove(resultTableAsArray[arrayIndex]);
174: incompleteDisplayList.remove(balance);
175: }
176: arrayIndex++;
177: }
178:
179: request.setAttribute(TOTALS_TABLE_KEY, totalsTable);
180: GlobalVariables.getUserSession().addObject(
181: TOTALS_TABLE_KEY, totalsTable);
182: } catch (NumberFormatException e) {
183: GlobalVariables
184: .getErrorMap()
185: .putError(
186: KFSPropertyConstants.UNIVERSITY_FISCAL_YEAR,
187: KFSKeyConstants.ERROR_CUSTOM,
188: new String[] { "Fiscal Year must be a four-digit number" });
189: } catch (Exception e) {
190: GlobalVariables
191: .getErrorMap()
192: .putError(
193: KFSConstants.DOCUMENT_ERRORS,
194: KFSKeyConstants.ERROR_CUSTOM,
195: new String[] { "Please report the server error." });
196: LOG.error("Application Errors", e);
197: }
198: }
199:
200: request.setAttribute(KFSConstants.REQUEST_SEARCH_RESULTS_SIZE,
201: totalSize);
202: request.setAttribute(KFSConstants.REQUEST_SEARCH_RESULTS,
203: resultTable);
204: lookupForm.setResultsActualSize((int) totalSize.longValue());
205: lookupForm.setResultsLimitedSize(resultTable.size());
206:
207: if (lookupForm.isSegmented()) {
208: LOG.debug("I'm segmented");
209: request
210: .setAttribute(
211: GLConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME,
212: Boolean.TRUE);
213: }
214:
215: if (request.getParameter(KFSConstants.SEARCH_LIST_REQUEST_KEY) != null) {
216: GlobalVariables
217: .getUserSession()
218: .removeObject(
219: request
220: .getParameter(KFSConstants.SEARCH_LIST_REQUEST_KEY));
221: request.setAttribute(KFSConstants.SEARCH_LIST_REQUEST_KEY,
222: GlobalVariables.getUserSession().addObject(
223: resultTable));
224: }
225:
226: return mapping.findForward(KFSConstants.MAPPING_BASIC);
227: }
228:
229: /**
230: * This method returns none of the selected results and redirects back to the lookup caller.
231: *
232: * @param mapping
233: * @param form must be an instance of MultipleValueLookupForm
234: * @param request
235: * @param response
236: * @return
237: * @throws Exception
238: */
239: public ActionForward prepareToReturnNone(ActionMapping mapping,
240: ActionForm form, HttpServletRequest request,
241: HttpServletResponse response) throws Exception {
242: MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
243: prepareToReturnNone(multipleValueLookupForm);
244:
245: // build the parameters for the refresh url
246: Properties parameters = new Properties();
247: parameters.put(KFSConstants.DOC_FORM_KEY,
248: multipleValueLookupForm.getFormKey());
249: parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER,
250: KFSConstants.RETURN_METHOD_TO_CALL);
251: parameters.put(KFSConstants.REFRESH_CALLER,
252: KFSConstants.MULTIPLE_VALUE);
253: parameters.put(KFSConstants.ANCHOR, multipleValueLookupForm
254: .getLookupAnchor());
255:
256: String backUrl = UrlFactory.parameterizeUrl(
257: multipleValueLookupForm.getBackLocation(), parameters);
258: return new ActionForward(backUrl, true);
259: }
260:
261: /**
262: * This method does the processing necessary to return selected results and sends a redirect back to the lookup caller
263: *
264: * @param mapping
265: * @param form must be an instance of MultipleValueLookupForm
266: * @param request
267: * @param response
268: * @return
269: * @throws Exception
270: */
271: public ActionForward prepareToReturnSelectedResults(
272: ActionMapping mapping, ActionForm form,
273: HttpServletRequest request, HttpServletResponse response)
274: throws Exception {
275: MultipleValueLookupForm multipleValueLookupForm = (MultipleValueLookupForm) form;
276: if (StringUtils.isBlank(multipleValueLookupForm
277: .getLookupResultsSequenceNumber())) {
278: // no search was executed
279: return prepareToReturnNone(mapping, form, request, response);
280: }
281:
282: prepareToReturnSelectedResultBOs(multipleValueLookupForm);
283:
284: // build the parameters for the refresh url
285: Properties parameters = new Properties();
286: parameters.put(KFSConstants.LOOKUP_RESULTS_BO_CLASS_NAME,
287: multipleValueLookupForm.getBusinessObjectClassName());
288: parameters.put(KFSConstants.LOOKUP_RESULTS_SEQUENCE_NUMBER,
289: multipleValueLookupForm
290: .getLookupResultsSequenceNumber());
291: parameters.put(KFSConstants.DOC_FORM_KEY,
292: multipleValueLookupForm.getFormKey());
293: parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER,
294: KFSConstants.RETURN_METHOD_TO_CALL);
295: parameters.put(KFSConstants.REFRESH_CALLER,
296: KFSConstants.MULTIPLE_VALUE);
297: parameters.put(KFSConstants.ANCHOR, multipleValueLookupForm
298: .getLookupAnchor());
299: String backUrl = UrlFactory.parameterizeUrl(
300: multipleValueLookupForm.getBackLocation(), parameters);
301: return new ActionForward(backUrl, true);
302: }
303:
304: /**
305: * @see org.kuali.core.web.struts.action.KualiMultipleValueLookupAction#sort(org.apache.struts.action.ActionMapping,
306: * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
307: */
308: @Override
309: public ActionForward sort(ActionMapping mapping, ActionForm form,
310: HttpServletRequest request, HttpServletResponse response)
311: throws Exception {
312: request
313: .setAttribute(
314: GLConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME,
315: Boolean.TRUE);
316: return super .sort(mapping, form, request, response);
317: }
318:
319: /**
320: * @see org.kuali.core.web.struts.action.KualiMultipleValueLookupAction#selectAll(org.apache.struts.action.ActionMapping,
321: * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
322: */
323: @Override
324: public ActionForward selectAll(ActionMapping mapping,
325: ActionForm form, HttpServletRequest request,
326: HttpServletResponse response) throws Exception {
327: request
328: .setAttribute(
329: GLConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME,
330: Boolean.TRUE);
331: return super .selectAll(mapping, form, request, response);
332: }
333:
334: /**
335: * @see org.kuali.core.web.struts.action.KualiMultipleValueLookupAction#unselectAll(org.apache.struts.action.ActionMapping,
336: * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
337: */
338: @Override
339: public ActionForward unselectAll(ActionMapping mapping,
340: ActionForm form, HttpServletRequest request,
341: HttpServletResponse response) throws Exception {
342: request
343: .setAttribute(
344: GLConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME,
345: Boolean.TRUE);
346: return super .unselectAll(mapping, form, request, response);
347: }
348:
349: /**
350: * @see org.kuali.core.web.struts.action.KualiMultipleValueLookupAction#switchToPage(org.apache.struts.action.ActionMapping,
351: * org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
352: */
353: @Override
354: public ActionForward switchToPage(ActionMapping mapping,
355: ActionForm form, HttpServletRequest request,
356: HttpServletResponse response) throws Exception {
357: request
358: .setAttribute(
359: GLConstants.LookupableBeanKeys.SEGMENTED_LOOKUP_FLAG_NAME,
360: Boolean.TRUE);
361: return super .switchToPage(mapping, form, request, response);
362: }
363:
364: /**
365: * This method performs the lookup and returns a collection of lookup items. Also initializes values in the form that will allow
366: * the multiple value lookup page to render
367: *
368: * @param multipleValueLookupForm
369: * @param resultTable a list of result rows (used to generate what's shown in the UI). This list will be modified by this method
370: * @param maxRowsPerPage
371: * @param bounded whether the results will be bounded
372: * @return the list of result BOs, possibly bounded by size
373: */
374: protected Collection performMultipleValueLookup(
375: MultipleValueLookupForm multipleValueLookupForm,
376: List<ResultRow> resultTable, int maxRowsPerPage,
377: boolean bounded) {
378: Lookupable lookupable = multipleValueLookupForm.getLookupable();
379: Collection displayList = lookupable.performLookup(
380: multipleValueLookupForm, resultTable, bounded);
381:
382: List defaultSortColumns = lookupable.getDefaultSortColumns();
383: if (defaultSortColumns != null && !defaultSortColumns.isEmpty()
384: && resultTable != null && !resultTable.isEmpty()) {
385: // there's a default sort order, just find the first sort column, and we can't go wrong
386: String firstSortColumn = (String) defaultSortColumns.get(0);
387:
388: // go thru the first result row to find the index of the column (more efficient than calling lookupable.getColumns since
389: // we don't have to recreate column list)
390: int firstSortColumnIdx = -1;
391: List<Column> columnsForFirstResultRow = resultTable.get(0)
392: .getColumns();
393: for (int i = 0; i < columnsForFirstResultRow.size(); i++) {
394: if (StringUtils.equals(firstSortColumn,
395: columnsForFirstResultRow.get(i)
396: .getPropertyName())) {
397: firstSortColumnIdx = i;
398: break;
399: }
400: }
401: multipleValueLookupForm
402: .setColumnToSortIndex(firstSortColumnIdx);
403: } else {
404: // don't know how results were sorted, so we just say -1
405: multipleValueLookupForm.setColumnToSortIndex(-1);
406: }
407:
408: // we just performed the lookup, so we're on the first page (indexed from 0)
409: multipleValueLookupForm.jumpToFirstPage(resultTable.size(),
410: maxRowsPerPage);
411:
412: SequenceAccessorService sequenceAccessorService = SpringContext
413: .getBean(SequenceAccessorService.class);
414: String lookupResultsSequenceNumber = String
415: .valueOf(sequenceAccessorService
416: .getNextAvailableSequenceNumber(KFSConstants.LOOKUP_RESULTS_SEQUENCE));
417: multipleValueLookupForm
418: .setLookupResultsSequenceNumber(lookupResultsSequenceNumber);
419: try {
420: LookupResultsService lookupResultsService = SpringContext
421: .getBean(LookupResultsService.class);
422: lookupResultsService.persistResultsTable(
423: lookupResultsSequenceNumber, resultTable,
424: GlobalVariables.getUserSession().getUniversalUser()
425: .getPersonUniversalIdentifier());
426: } catch (Exception e) {
427: LOG
428: .error(
429: "error occured trying to persist multiple lookup results",
430: e);
431: throw new RuntimeException(
432: "error occured trying to persist multiple lookup results");
433: }
434:
435: // since new search, nothing's checked
436: multipleValueLookupForm
437: .setCompositeObjectIdMap(new HashMap<String, String>());
438:
439: return displayList;
440: }
441: }
|