001    /*
002     * Copyright 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.kfs.pdp.web.struts;
017    
018    import java.text.MessageFormat;
019    import java.util.List;
020    import java.util.Properties;
021    
022    import javax.servlet.http.HttpServletRequest;
023    import javax.servlet.http.HttpServletResponse;
024    
025    import org.apache.commons.lang.StringUtils;
026    import org.apache.struts.action.ActionForm;
027    import org.apache.struts.action.ActionForward;
028    import org.apache.struts.action.ActionMapping;
029    import org.kuali.kfs.pdp.PdpKeyConstants;
030    import org.kuali.kfs.pdp.PdpParameterConstants;
031    import org.kuali.kfs.pdp.PdpPropertyConstants;
032    import org.kuali.kfs.pdp.businessobject.Batch;
033    import org.kuali.kfs.pdp.service.BatchMaintenanceService;
034    import org.kuali.kfs.pdp.util.PdpBatchQuestionCallback;
035    import org.kuali.kfs.sys.KFSConstants;
036    import org.kuali.kfs.sys.context.SpringContext;
037    import org.kuali.rice.kim.bo.Person;
038    import org.kuali.rice.kns.question.ConfirmationQuestion;
039    import org.kuali.rice.kns.service.KNSServiceLocator;
040    import org.kuali.rice.kns.service.KualiConfigurationService;
041    import org.kuali.rice.kns.util.ErrorMessage;
042    import org.kuali.rice.kns.util.GlobalVariables;
043    import org.kuali.rice.kns.util.KNSConstants;
044    import org.kuali.rice.kns.util.MessageMap;
045    import org.kuali.rice.kns.util.UrlFactory;
046    import org.kuali.rice.kns.web.struts.action.KualiAction;
047    
048    /**
049     * This class defines actions for Batch (cancel, hold, remove hold).
050     */
051    public class BatchAction extends KualiAction {
052    
053        private BatchMaintenanceService batchMaintenanceService;
054    
055        /**
056         * Constructs a BatchAction.java.
057         */
058        public BatchAction() {
059            setBatchMaintenanceService(SpringContext.getBean(BatchMaintenanceService.class));
060        }
061    
062    
063        /**
064         * This method confirms and performs batch cancel.
065         * 
066         * @param mapping
067         * @param form
068         * @param request
069         * @param response
070         * @return
071         * @throws Exception
072         */
073        public ActionForward confirmAndCancel(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
074    
075            PdpBatchQuestionCallback callback = new PdpBatchQuestionCallback() {
076                public boolean doPostQuestion(String batchIdString, String cancelNote, Person user) {
077                    return performCancel(batchIdString, cancelNote, user);
078                }
079            };
080            return askQuestionWithInput(mapping, form, request, response, PdpKeyConstants.BatchConstants.Confirmation.CANCEL_BATCH_QUESTION, PdpKeyConstants.BatchConstants.Confirmation.CANCEL_BATCH_MESSAGE, PdpKeyConstants.BatchConstants.Messages.BATCH_SUCCESSFULLY_CANCELED, "confirmAndCancel", callback);
081    
082        }
083    
084        /**
085         * This method cancels a batch.
086         * 
087         * @param batchIdString a string representing the batch id
088         * @param cancelNote the cancelation note entered by the user
089         * @param user the current user
090         */
091        private boolean performCancel(String batchIdString, String cancelNote, Person user) {
092            try {
093                Integer batchId = Integer.parseInt(batchIdString);
094                return batchMaintenanceService.cancelPendingBatch(batchId, cancelNote, user);
095            }
096            catch (NumberFormatException e) {
097                GlobalVariables.getMessageMap().putError(PdpPropertyConstants.BatchConstants.BATCH_ID, PdpKeyConstants.BatchConstants.ErrorMessages.ERROR_BATCH_ID_IS_NOT_NUMERIC);
098                return false;
099            }
100    
101        }
102    
103        /**
104         * This method confirms and performs batch hold.
105         * 
106         * @param mapping
107         * @param form
108         * @param request
109         * @param response
110         * @return
111         * @throws Exception
112         */
113        public ActionForward confirmAndHold(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
114    
115            PdpBatchQuestionCallback callback = new PdpBatchQuestionCallback() {
116                public boolean doPostQuestion(String batchIdString, String note, Person user) {
117                    return performHold(batchIdString, note, user);
118                }
119            };
120            return askQuestionWithInput(mapping, form, request, response, PdpKeyConstants.BatchConstants.Confirmation.HOLD_BATCH_QUESTION, PdpKeyConstants.BatchConstants.Confirmation.HOLD_BATCH_MESSAGE, PdpKeyConstants.BatchConstants.Messages.BATCH_SUCCESSFULLY_HOLD, "confirmAndHold", callback);
121        }
122    
123        /**
124         * This method holds a batch
125         * 
126         * @param batchIdString
127         * @param holdNote
128         * @param user
129         * @throws PdpException
130         */
131        private boolean performHold(String batchIdString, String holdNote, Person user) {
132            try {
133                Integer batchId = Integer.parseInt(batchIdString);
134                return batchMaintenanceService.holdPendingBatch(batchId, holdNote, user);
135            }
136            catch (NumberFormatException e) {
137                GlobalVariables.getMessageMap().putError(PdpPropertyConstants.BatchConstants.BATCH_ID, PdpKeyConstants.BatchConstants.ErrorMessages.ERROR_BATCH_ID_IS_NOT_NUMERIC);
138                return false;
139            }
140    
141        }
142    
143        /**
144         * This method confirms and peforms remove hold on batch action.
145         * 
146         * @param mapping
147         * @param form
148         * @param request
149         * @param response
150         * @return
151         * @throws Exception
152         */
153        public ActionForward confirmAndRemoveHold(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
154            PdpBatchQuestionCallback callback = new PdpBatchQuestionCallback() {
155                public boolean doPostQuestion(String batchIdString, String note, Person user) {
156                    return performRemoveHold(batchIdString, note, user);
157                }
158            };
159            return askQuestionWithInput(mapping, form, request, response, PdpKeyConstants.BatchConstants.Confirmation.REMOVE_HOLD_BATCH_QUESTION, PdpKeyConstants.BatchConstants.Confirmation.REMOVE_HOLD_BATCH_MESSAGE, PdpKeyConstants.BatchConstants.Messages.HOLD_SUCCESSFULLY_REMOVED_ON_BATCH, "confirmAndRemoveHold", callback);
160        }
161    
162        /**
163         * This method removes a batch hold.
164         * 
165         * @param batchIdString
166         * @param changeText
167         * @param user
168         * @throws PdpException
169         */
170        private boolean performRemoveHold(String batchIdString, String changeText, Person user) {
171            try {
172                Integer batchId = Integer.parseInt(batchIdString);
173                return batchMaintenanceService.removeBatchHold(batchId, changeText, user);
174            }
175            catch (NumberFormatException e) {
176                GlobalVariables.getMessageMap().putError(PdpPropertyConstants.BatchConstants.BATCH_ID, PdpKeyConstants.BatchConstants.ErrorMessages.ERROR_BATCH_ID_IS_NOT_NUMERIC);
177                return false;
178            }
179    
180        }
181    
182        /**
183         * This method prompts for a reason to perfomr an action on a batch (cancel, hold, remove hold).
184         * 
185         * @param mapping
186         * @param form
187         * @param request
188         * @param response
189         * @param confirmationQuestion
190         * @param confirmationText
191         * @param caller
192         * @param callback
193         * @return
194         * @throws Exception
195         */
196        private ActionForward askQuestionWithInput(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, String confirmationQuestion, String confirmationText, String successMessage, String caller, PdpBatchQuestionCallback callback) throws Exception {
197            Object question = request.getParameter(KNSConstants.QUESTION_INST_ATTRIBUTE_NAME);
198            String reason = request.getParameter(KNSConstants.QUESTION_REASON_ATTRIBUTE_NAME);
199            String noteText = KFSConstants.EMPTY_STRING;
200            Person person = GlobalVariables.getUserSession().getPerson();
201            boolean actionStatus;
202            String message = KFSConstants.EMPTY_STRING;
203    
204            String batchId = request.getParameter(PdpParameterConstants.BatchConstants.BATCH_ID_PARAM);
205            if (batchId == null) {
206                batchId = request.getParameter(KNSConstants.QUESTION_CONTEXT);
207            }
208    
209            KualiConfigurationService kualiConfiguration = KNSServiceLocator.getKualiConfigurationService();
210            confirmationText = kualiConfiguration.getPropertyString(confirmationText);
211            confirmationText = MessageFormat.format(confirmationText, batchId);
212    
213            if (question == null) {
214                // ask question if not already asked
215                return this.performQuestionWithInput(mapping, form, request, response, confirmationQuestion, confirmationText, KNSConstants.CONFIRMATION_QUESTION, caller, batchId);
216            }
217            else {
218                Object buttonClicked = request.getParameter(KNSConstants.QUESTION_CLICKED_BUTTON);
219                if ((confirmationQuestion.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {
220                    actionStatus = false;
221                }
222                else {
223                    noteText = reason;
224                    int noteTextLength = (reason == null) ? 0 : noteText.length();
225                    int noteTextMaxLength = PdpKeyConstants.BatchConstants.Confirmation.NOTE_TEXT_MAX_LENGTH;
226    
227                    if (StringUtils.isBlank(reason)) {
228    
229                        if (reason == null) {
230                            // prevent a NPE by setting the reason to a blank string
231                            reason = KFSConstants.EMPTY_STRING;
232                        }
233                        return this.performQuestionWithInputAgainBecauseOfErrors(mapping, form, request, response, confirmationQuestion, confirmationText, KNSConstants.CONFIRMATION_QUESTION, KFSConstants.MAPPING_BASIC, batchId, reason, PdpKeyConstants.BatchConstants.ErrorMessages.ERROR_NOTE_EMPTY, KNSConstants.QUESTION_REASON_ATTRIBUTE_NAME, "");
234                    }
235                    else if (noteTextLength > noteTextMaxLength) {
236                        return this.performQuestionWithInputAgainBecauseOfErrors(mapping, form, request, response, confirmationQuestion, confirmationText, KNSConstants.CONFIRMATION_QUESTION, KFSConstants.MAPPING_BASIC, batchId, reason, PdpKeyConstants.BatchConstants.ErrorMessages.ERROR_NOTE_TOO_LONG, KNSConstants.QUESTION_REASON_ATTRIBUTE_NAME, "");
237                    }
238    
239                    actionStatus = callback.doPostQuestion(batchId, noteText, person);
240                    if (actionStatus) {
241                        message = successMessage;
242                    }
243    
244                }
245            }
246    
247            String returnUrl = buildUrl(batchId, actionStatus, message, buildErrorMesageKeyList());
248            return new ActionForward(returnUrl, true);
249        }
250    
251        /**
252         * This method builds the forward url.
253         * 
254         * @param batchId the batch id
255         * @param success action status: true if success, false otherwise
256         * @param message the message for the user
257         * @return the build url
258         */
259        private String buildUrl(String batchId, boolean success, String message, String errorList) {
260            String basePath = SpringContext.getBean(KualiConfigurationService.class).getPropertyString(KFSConstants.APPLICATION_URL_KEY);
261    
262            Properties parameters = new Properties();
263            parameters.put(KFSConstants.DISPATCH_REQUEST_PARAMETER, KFSConstants.SEARCH_METHOD);
264            parameters.put(KFSConstants.BACK_LOCATION, basePath + "/" + KFSConstants.MAPPING_PORTAL + ".do");
265            parameters.put(KNSConstants.DOC_FORM_KEY, "88888888");
266            parameters.put(KFSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, Batch.class.getName());
267            parameters.put(KFSConstants.HIDE_LOOKUP_RETURN_LINK, "true");
268            parameters.put(KFSConstants.SUPPRESS_ACTIONS, "false");
269            parameters.put(PdpPropertyConstants.BatchConstants.BATCH_ID, batchId);
270            parameters.put(PdpParameterConstants.ACTION_SUCCESSFUL_PARAM, String.valueOf(success));
271            if (message != null && !message.equalsIgnoreCase(KFSConstants.EMPTY_STRING)) {
272                parameters.put(PdpParameterConstants.MESSAGE_PARAM, message);
273            }
274    
275            if (StringUtils.isNotEmpty(errorList)) {
276                parameters.put(PdpParameterConstants.ERROR_KEY_LIST_PARAM, errorList);
277            }
278    
279            String lookupUrl = UrlFactory.parameterizeUrl(basePath + "/" + KFSConstants.LOOKUP_ACTION, parameters);
280    
281            return lookupUrl;
282        }
283    
284        /**
285         * This method build a string list of error message keys out of the error map in GlobalVariables
286         * 
287         * @return a String representing the list of error message keys
288         */
289        private String buildErrorMesageKeyList() {
290            MessageMap errorMap = GlobalVariables.getMessageMap();
291            StringBuffer errorList = new StringBuffer();
292    
293            for (String errorKey : (List<String>) errorMap.getPropertiesWithErrors()) {
294                for (ErrorMessage errorMessage : (List<ErrorMessage>) errorMap.getMessages(errorKey)) {
295    
296                    errorList.append(errorMessage.getErrorKey());
297                    errorList.append(PdpParameterConstants.ERROR_KEY_LIST_SEPARATOR);
298                }
299            }
300            if (errorList.length() > 0) {
301                errorList.replace(errorList.lastIndexOf(PdpParameterConstants.ERROR_KEY_LIST_SEPARATOR), errorList.lastIndexOf(PdpParameterConstants.ERROR_KEY_LIST_SEPARATOR) + PdpParameterConstants.ERROR_KEY_LIST_SEPARATOR.length(), "");
302            }
303    
304            return errorList.toString();
305        }
306    
307        /**
308         * This method gets the batch maintenance service.
309         * 
310         * @return the BatchMaintenanceService
311         */
312        public BatchMaintenanceService getBatchMaintenanceService() {
313            return batchMaintenanceService;
314        }
315    
316        /**
317         * This method sets the batch maintenance service.
318         * 
319         * @param batchMaintenanceService
320         */
321        public void setBatchMaintenanceService(BatchMaintenanceService batchMaintenanceService) {
322            this.batchMaintenanceService = batchMaintenanceService;
323        }
324    
325    }
326