Coverage Report - org.kuali.rice.krad.web.controller.DocumentControllerBase
 
Classes in this File Line Coverage Branch Coverage Complexity
DocumentControllerBase
0%
0/225
0%
0/91
2.818
DocumentControllerBase$1
0%
0/1
N/A
2.818
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.krad.web.controller;
 17  
 
 18  
 import org.apache.commons.lang.ArrayUtils;
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.kuali.rice.core.api.config.property.ConfigurationService;
 21  
 import org.kuali.rice.core.api.exception.RiceRuntimeException;
 22  
 import org.kuali.rice.core.api.util.RiceKeyConstants;
 23  
 import org.kuali.rice.core.framework.parameter.ParameterConstants;
 24  
 import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
 25  
 import org.kuali.rice.kew.api.KewApiConstants;
 26  
 import org.kuali.rice.kew.api.WorkflowDocument;
 27  
 import org.kuali.rice.kew.api.exception.WorkflowException;
 28  
 import org.kuali.rice.kim.api.identity.Person;
 29  
 import org.kuali.rice.krad.bo.AdHocRouteRecipient;
 30  
 import org.kuali.rice.krad.bo.Attachment;
 31  
 import org.kuali.rice.krad.bo.DocumentHeader;
 32  
 import org.kuali.rice.krad.bo.Note;
 33  
 import org.kuali.rice.krad.document.Document;
 34  
 import org.kuali.rice.krad.document.MaintenanceDocument;
 35  
 import org.kuali.rice.krad.document.authorization.DocumentAuthorizer;
 36  
 import org.kuali.rice.krad.exception.DocumentAuthorizationException;
 37  
 import org.kuali.rice.krad.exception.UnknownDocumentIdException;
 38  
 import org.kuali.rice.krad.exception.ValidationException;
 39  
 import org.kuali.rice.krad.question.ConfirmationQuestion;
 40  
 import org.kuali.rice.krad.rule.event.AddNoteEvent;
 41  
 import org.kuali.rice.krad.service.AttachmentService;
 42  
 import org.kuali.rice.krad.service.BusinessObjectService;
 43  
 import org.kuali.rice.krad.service.DataDictionaryService;
 44  
 import org.kuali.rice.krad.service.DocumentHelperService;
 45  
 import org.kuali.rice.krad.service.DocumentService;
 46  
 import org.kuali.rice.krad.service.KRADServiceLocator;
 47  
 import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
 48  
 import org.kuali.rice.krad.service.NoteService;
 49  
 import org.kuali.rice.krad.uif.UifConstants.WorkflowAction;
 50  
 import org.kuali.rice.krad.uif.UifParameters;
 51  
 import org.kuali.rice.krad.uif.UifPropertyPaths;
 52  
 import org.kuali.rice.krad.uif.container.CollectionGroup;
 53  
 import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
 54  
 import org.kuali.rice.krad.util.GlobalVariables;
 55  
 import org.kuali.rice.krad.util.KRADConstants;
 56  
 import org.kuali.rice.krad.util.KRADPropertyConstants;
 57  
 import org.kuali.rice.krad.util.KRADUtils;
 58  
 import org.kuali.rice.krad.util.NoteType;
 59  
 import org.kuali.rice.krad.util.SessionTicket;
 60  
 import org.kuali.rice.krad.web.form.DocumentFormBase;
 61  
 import org.kuali.rice.krad.web.form.UifFormBase;
 62  
 import org.springframework.util.FileCopyUtils;
 63  
 import org.springframework.validation.BindingResult;
 64  
 import org.springframework.web.bind.ServletRequestBindingException;
 65  
 import org.springframework.web.bind.annotation.ModelAttribute;
 66  
 import org.springframework.web.bind.annotation.RequestMapping;
 67  
 import org.springframework.web.bind.annotation.RequestMethod;
 68  
 import org.springframework.web.multipart.MultipartFile;
 69  
 import org.springframework.web.servlet.ModelAndView;
 70  
 
 71  
 import javax.servlet.http.HttpServletRequest;
 72  
 import javax.servlet.http.HttpServletResponse;
 73  
 import java.io.FileNotFoundException;
 74  
 import java.io.IOException;
 75  
 import java.io.InputStream;
 76  
 import java.util.ArrayList;
 77  
 import java.util.HashMap;
 78  
 import java.util.List;
 79  
 import java.util.Map;
 80  
 import java.util.Properties;
 81  
 
 82  
 /**
 83  
  * Base controller class for all KRAD <code>DocumentView</code> screens working
 84  
  * with <code>Document</code> models
 85  
  *
 86  
  * <p>
 87  
  * Provides default controller implementations for the standard document actions including: doc handler
 88  
  * (retrieve from doc search and action list), save, route (and other KEW actions)
 89  
  * </p>
 90  
  *
 91  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 92  
  */
 93  0
 public abstract class DocumentControllerBase extends UifControllerBase {
 94  0
     private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(DocumentControllerBase.class);
 95  
 
 96  
     // COMMAND constants which cause docHandler to load an existing document
 97  
     // instead of creating a new one
 98  0
     protected static final String[] DOCUMENT_LOAD_COMMANDS =
 99  
             {KewApiConstants.ACTIONLIST_COMMAND, KewApiConstants.DOCSEARCH_COMMAND, KewApiConstants.SUPERUSER_COMMAND,
 100  
                     KewApiConstants.HELPDESK_ACTIONLIST_COMMAND};
 101  
 
 102  
     private BusinessObjectService businessObjectService;
 103  
     private DataDictionaryService dataDictionaryService;
 104  
     private DocumentService documentService;
 105  
     private DocumentHelperService documentHelperService;
 106  
     private AttachmentService attachmentService;
 107  
     private NoteService noteService;
 108  
 
 109  
     
 110  
     /**
 111  
      * @see org.kuali.rice.krad.web.controller.UifControllerBase#createInitialForm(javax.servlet.http.HttpServletRequest)
 112  
      */
 113  
     @Override
 114  
     protected abstract DocumentFormBase createInitialForm(HttpServletRequest request);
 115  
 
 116  
     /**
 117  
      * Used to funnel all document handling through, we could do useful things
 118  
      * like log and record various openings and status Additionally it may be
 119  
      * nice to have a single dispatcher that can know how to dispatch to a
 120  
      * redirect url for document specific handling but we may not need that as
 121  
      * all we should need is the document to be able to load itself based on
 122  
      * document id and then which action forward or redirect is pertinent for
 123  
      * the document type.
 124  
      */
 125  
     @RequestMapping(params = "methodToCall=docHandler")
 126  
     public ModelAndView docHandler(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 127  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 128  0
         String command = form.getCommand();
 129  
 
 130  
         // in all of the following cases we want to load the document
 131  0
         if (ArrayUtils.contains(DOCUMENT_LOAD_COMMANDS, command) && form.getDocId() != null) {
 132  0
             loadDocument(form);
 133  0
         } else if (KewApiConstants.INITIATE_COMMAND.equals(command)) {
 134  0
             createDocument(form);
 135  
         } else {
 136  0
             LOG.error("docHandler called with invalid parameters");
 137  0
             throw new IllegalStateException("docHandler called with invalid parameters");
 138  
         }
 139  
 
 140  
         // TODO: authorization on document actions
 141  
         // if (KEWConstants.SUPERUSER_COMMAND.equalsIgnoreCase(command)) {
 142  
         // form.setSuppressAllButtons(true);
 143  
         // }
 144  
 
 145  0
         return getUIFModelAndView(form);
 146  
     }
 147  
 
 148  
     /**
 149  
      * Loads the document by its provided document header id. This has been abstracted out so that
 150  
      * it can be overridden in children if the need arises
 151  
      *
 152  
      * @param form - form instance that contains the doc id parameter and where
 153  
      * the retrieved document instance should be set
 154  
      */
 155  
     protected void loadDocument(DocumentFormBase form) throws WorkflowException {
 156  0
         String docId = form.getDocId();
 157  
 
 158  0
         LOG.debug("Loading document" + docId);
 159  
 
 160  0
         Document doc = null;
 161  0
         doc = getDocumentService().getByDocumentHeaderId(docId);
 162  0
         if (doc == null) {
 163  0
             throw new UnknownDocumentIdException(
 164  
                     "Document no longer exists.  It may have been cancelled before being saved.");
 165  
         }
 166  
 
 167  0
         WorkflowDocument workflowDocument = doc.getDocumentHeader().getWorkflowDocument();
 168  0
         if (!getDocumentHelperService().getDocumentAuthorizer(doc).canOpen(doc,
 169  
                 GlobalVariables.getUserSession().getPerson())) {
 170  0
             throw buildAuthorizationException("open", doc);
 171  
         }
 172  
 
 173  
         // re-retrieve the document using the current user's session - remove
 174  
         // the system user from the WorkflowDcument object
 175  0
         if (workflowDocument != doc.getDocumentHeader().getWorkflowDocument()) {
 176  0
             LOG.warn("Workflow document changed via canOpen check");
 177  0
             doc.getDocumentHeader().setWorkflowDocument(workflowDocument);
 178  
         }
 179  
 
 180  0
         form.setDocument(doc);
 181  0
         WorkflowDocument workflowDoc = doc.getDocumentHeader().getWorkflowDocument();
 182  0
         form.setDocTypeName(workflowDoc.getDocumentTypeName());
 183  
 
 184  0
         KRADServiceLocatorWeb.getSessionDocumentService().addDocumentToUserSession(GlobalVariables.getUserSession(),
 185  
                 workflowDoc);
 186  0
     }
 187  
 
 188  
     /**
 189  
      * Creates a new document of the type specified by the docTypeName property of the given form.
 190  
      * This has been abstracted out so that it can be overridden in children if the need arises.
 191  
      *
 192  
      * @param form - form instance that contains the doc type parameter and where
 193  
      * the new document instance should be set
 194  
      */
 195  
     protected void createDocument(DocumentFormBase form) throws WorkflowException {
 196  0
         LOG.debug("Creating new document instance for doc type: " + form.getDocTypeName());
 197  0
         Document doc = getDocumentService().getNewDocument(form.getDocTypeName());
 198  
 
 199  0
         form.setDocument(doc);
 200  0
         form.setDocTypeName(doc.getDocumentHeader().getWorkflowDocument().getDocumentTypeName());
 201  0
     }
 202  
 
 203  
     /**
 204  
      * Reloads the document contained on the form from the database
 205  
      *
 206  
      * @param form - document form base containing the document instance from which the document number will
 207  
      * be retrieved and used to fetch the document from the database
 208  
      * @return ModelAndView
 209  
      */
 210  
     @RequestMapping(params = "methodToCall=reload")
 211  
     public ModelAndView reload(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 212  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 213  0
         Document document = form.getDocument();
 214  
 
 215  
         // prepare for the reload action - set doc id and command
 216  0
         form.setDocId(document.getDocumentNumber());
 217  0
         form.setCommand(DOCUMENT_LOAD_COMMANDS[1]);
 218  
 
 219  0
         GlobalVariables.getMessageMap().putInfo(KRADConstants.GLOBAL_MESSAGES, RiceKeyConstants.MESSAGE_RELOADED);
 220  
 
 221  
         // forward off to the doc handler
 222  0
         return docHandler(form, result, request, response);
 223  
     }
 224  
 
 225  
     /**
 226  
      * Prompts user to confirm the cancel action then if confirmed cancels the document instance
 227  
      * contained on the form
 228  
      *
 229  
      * @param form - document form base containing the document instance that will be cancelled
 230  
      * @return ModelAndView
 231  
      */
 232  
     @RequestMapping(params = "methodToCall=cancel")
 233  
     @Override
 234  
     public ModelAndView cancel(@ModelAttribute("KualiForm") UifFormBase form, BindingResult result,
 235  
             HttpServletRequest request, HttpServletResponse response) {
 236  0
         DocumentFormBase documentForm = (DocumentFormBase) form;
 237  
 
 238  
         // TODO: prompt user to confirm the cancel, need question framework
 239  
 
 240  0
         performWorkflowAction(documentForm, WorkflowAction.CANCEL, false);
 241  
 
 242  0
         return returnToPrevious(form);
 243  
     }
 244  
 
 245  
     /**
 246  
      * Saves the document instance contained on the form
 247  
      *
 248  
      * @param form - document form base containing the document instance that will be saved
 249  
      * @return ModelAndView
 250  
      */
 251  
     @RequestMapping(params = "methodToCall=save")
 252  
     public ModelAndView save(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 253  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 254  0
         performWorkflowAction(form, WorkflowAction.SAVE, true);
 255  
 
 256  0
         return getUIFModelAndView(form);
 257  
     }
 258  
 
 259  
     /**
 260  
      * Routes the document instance contained on the form
 261  
      *
 262  
      * @param form - document form base containing the document instance that will be routed
 263  
      * @return ModelAndView
 264  
      */
 265  
     @RequestMapping(params = "methodToCall=route")
 266  
     public ModelAndView route(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 267  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 268  0
         performWorkflowAction(form, WorkflowAction.ROUTE, true);
 269  
 
 270  0
         return getUIFModelAndView(form);
 271  
     }
 272  
 
 273  
     /**
 274  
      * Performs the blanket approve workflow action on the form document instance
 275  
      *
 276  
      * @param form - document form base containing the document instance that will be blanket approved
 277  
      * @return ModelAndView
 278  
      */
 279  
     @RequestMapping(params = "methodToCall=blanketApprove")
 280  
     public ModelAndView blanketApprove(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 281  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 282  0
         performWorkflowAction(form, WorkflowAction.BLANKETAPPROVE, true);
 283  
 
 284  0
         return returnToPrevious(form);
 285  
     }
 286  
 
 287  
     /**
 288  
      * Performs the approve workflow action on the form document instance
 289  
      *
 290  
      * @param form - document form base containing the document instance that will be approved
 291  
      * @return ModelAndView
 292  
      */
 293  
     @RequestMapping(params = "methodToCall=approve")
 294  
     public ModelAndView approve(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 295  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 296  0
         performWorkflowAction(form, WorkflowAction.APPROVE, true);
 297  
 
 298  0
         return returnToPrevious(form);
 299  
     }
 300  
 
 301  
     /**
 302  
      * Performs the disapprove workflow action on the form document instance
 303  
      *
 304  
      * @param form - document form base containing the document instance that will be disapproved
 305  
      * @return ModelAndView
 306  
      */
 307  
     @RequestMapping(params = "methodToCall=disapprove")
 308  
     public ModelAndView disapprove(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 309  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 310  
         // TODO: need to prompt for disapproval note text
 311  0
         performWorkflowAction(form, WorkflowAction.DISAPPROVE, true);
 312  
 
 313  0
         return returnToPrevious(form);
 314  
     }
 315  
 
 316  
     /**
 317  
      * Performs the fyi workflow action on the form document instance
 318  
      *
 319  
      * @param form - document form base containing the document instance the fyi will be taken on
 320  
      * @return ModelAndView
 321  
      */
 322  
     @RequestMapping(params = "methodToCall=fyi")
 323  
     public ModelAndView fyi(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 324  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 325  0
         performWorkflowAction(form, WorkflowAction.FYI, false);
 326  
 
 327  0
         return returnToPrevious(form);
 328  
     }
 329  
 
 330  
     /**
 331  
      * Performs the acknowledge workflow action on the form document instance
 332  
      *
 333  
      * @param form - document form base containing the document instance the acknowledge will be taken on
 334  
      * @return ModelAndView
 335  
      */
 336  
     @RequestMapping(params = "methodToCall=acknowledge")
 337  
     public ModelAndView acknowledge(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 338  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 339  0
         performWorkflowAction(form, WorkflowAction.ACKNOWLEDGE, false);
 340  
 
 341  0
         return returnToPrevious(form);
 342  
     }
 343  
 
 344  
     /**
 345  
      * Invokes the {@link DocumentService} to carry out a request workflow action and adds a success message, if
 346  
      * requested a check for sensitive data is also performed
 347  
      *
 348  
      * @param form - document form instance containing the document for which the action will be taken on
 349  
      * @param action - {@link WorkflowAction} enum indicating what workflow action to take
 350  
      * @param checkSensitiveData - boolean indicating whether a check for sensitive data should occur
 351  
      */
 352  
     protected void performWorkflowAction(DocumentFormBase form, WorkflowAction action, boolean checkSensitiveData) {
 353  0
         Document document = form.getDocument();
 354  
 
 355  0
         LOG.debug("Performing workflow action " + action.name() + "for document: " + document.getDocumentNumber());
 356  
 
 357  
         // TODO: need question and prompt framework
 358  0
         if (checkSensitiveData) {
 359  
             //        String viewName = checkAndWarnAboutSensitiveData(form, request, response,
 360  
             //                KRADPropertyConstants.DOCUMENT_EXPLANATION, document.getDocumentHeader().getExplanation(), "route", "");
 361  
             //        if (viewName != null) {
 362  
             //            return new ModelAndView(viewName);
 363  
             //        }
 364  
         }
 365  
 
 366  
         try {
 367  0
             String successMessageKey = null;
 368  0
             switch (action) {
 369  
                 case SAVE:
 370  0
                     getDocumentService().saveDocument(document);
 371  0
                     successMessageKey = RiceKeyConstants.MESSAGE_SAVED;
 372  0
                     break;
 373  
                 case ROUTE:
 374  0
                     getDocumentService().routeDocument(document, form.getAnnotation(), combineAdHocRecipients(form));
 375  0
                     successMessageKey = RiceKeyConstants.MESSAGE_ROUTE_SUCCESSFUL;
 376  0
                     break;
 377  
                 case BLANKETAPPROVE:
 378  0
                     getDocumentService().blanketApproveDocument(document, form.getAnnotation(), combineAdHocRecipients(
 379  
                             form));
 380  0
                     successMessageKey = RiceKeyConstants.MESSAGE_ROUTE_APPROVED;
 381  0
                     break;
 382  
                 case APPROVE:
 383  0
                     getDocumentService().approveDocument(document, form.getAnnotation(), combineAdHocRecipients(form));
 384  0
                     successMessageKey = RiceKeyConstants.MESSAGE_ROUTE_APPROVED;
 385  0
                     break;
 386  
                 case DISAPPROVE:
 387  
                     // TODO: need to get disapprove note from user
 388  0
                     String disapprovalNoteText = "";
 389  0
                     getDocumentService().disapproveDocument(document, disapprovalNoteText);
 390  0
                     successMessageKey = RiceKeyConstants.MESSAGE_ROUTE_DISAPPROVED;
 391  0
                     break;
 392  
                 case FYI:
 393  0
                     getDocumentService().clearDocumentFyi(document, combineAdHocRecipients(form));
 394  0
                     successMessageKey = RiceKeyConstants.MESSAGE_ROUTE_FYIED;
 395  0
                     break;
 396  
                 case ACKNOWLEDGE:
 397  0
                     getDocumentService().acknowledgeDocument(document, form.getAnnotation(), combineAdHocRecipients(
 398  
                             form));
 399  0
                     successMessageKey = RiceKeyConstants.MESSAGE_ROUTE_ACKNOWLEDGED;
 400  0
                     break;
 401  
                 case CANCEL:
 402  0
                     if (getDocumentService().documentExists(document.getDocumentNumber())) {
 403  0
                         getDocumentService().cancelDocument(document, form.getAnnotation());
 404  0
                         successMessageKey = RiceKeyConstants.MESSAGE_CANCELLED;
 405  
                     }
 406  0
                     break;
 407  
             }
 408  
 
 409  0
             if (successMessageKey != null) {
 410  0
                 GlobalVariables.getMessageMap().putInfo(KRADConstants.GLOBAL_MESSAGES, successMessageKey);
 411  
             }
 412  0
         } catch (ValidationException e) {
 413  
             // if errors in map, swallow exception so screen will draw with errors
 414  
             // if not then throw runtime because something bad happened
 415  0
             if (GlobalVariables.getMessageMap().hasNoErrors()) {
 416  0
                 throw new RiceRuntimeException("Validation Exception with no error message.", e);
 417  
             }
 418  0
         } catch (Exception e) {
 419  0
             throw new RiceRuntimeException(
 420  
                     "Exception trying to invoke action " + action.name() + "for document: " + document
 421  
                             .getDocumentNumber(), e);
 422  0
         }
 423  
 
 424  0
         form.setAnnotation("");
 425  0
     }
 426  
 
 427  
     /**
 428  
      * Redirects to the supervisor functions page
 429  
      *
 430  
      * @return ModelAndView - model and view configured for the redirect URL
 431  
      */
 432  
     @RequestMapping(params = "methodToCall=supervisorFunctions")
 433  
     public ModelAndView supervisorFunctions(@ModelAttribute("KualiForm") DocumentFormBase form, BindingResult result,
 434  
             HttpServletRequest request, HttpServletResponse response) throws Exception {
 435  
 
 436  0
         String workflowSuperUserUrl = getConfigurationService().getPropertyValueAsString(KRADConstants.WORKFLOW_URL_KEY)
 437  
                 + "/" + KRADConstants.SUPERUSER_ACTION;
 438  
 
 439  0
         Properties props = new Properties();
 440  0
         props.put(UifParameters.METHOD_TO_CALL, "displaySuperUserDocument");
 441  0
         props.put(UifPropertyPaths.DOCUMENT_ID, form.getDocument().getDocumentNumber());
 442  
 
 443  0
         return performRedirect(form, workflowSuperUserUrl, props);
 444  
     }
 445  
 
 446  
     /**
 447  
      * Called by the add note action for adding a note. Method validates, saves attachment and adds the
 448  
      * time stamp and author. Calls the UifControllerBase.addLine method to handle generic actions.
 449  
      *
 450  
      * @param form - document form base containing the note instance that will be inserted into the document
 451  
      * @return ModelAndView
 452  
      */
 453  
     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=insertNote")
 454  
     public ModelAndView insertNote(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
 455  
             HttpServletRequest request, HttpServletResponse response) {
 456  
 
 457  
         // Get the note add line
 458  0
         String selectedCollectionPath = uifForm.getActionParamaterValue(UifParameters.SELLECTED_COLLECTION_PATH);
 459  0
         CollectionGroup collectionGroup = uifForm.getPreviousView().getViewIndex().getCollectionGroupByPath(
 460  
                 selectedCollectionPath);
 461  0
         String addLinePath = collectionGroup.getAddLineBindingInfo().getBindingPath();
 462  0
         Object addLine = ObjectPropertyUtils.getPropertyValue(uifForm, addLinePath);
 463  0
         Note newNote = (Note) addLine;
 464  0
         newNote.setNotePostedTimestampToCurrent();
 465  
 
 466  0
         Document document = ((DocumentFormBase) uifForm).getDocument();
 467  
 
 468  0
         newNote.setRemoteObjectIdentifier(document.getNoteTarget().getObjectId());
 469  
 
 470  
         // Get the attachment file
 471  0
         String attachmentTypeCode = null;
 472  0
         MultipartFile attachmentFile = uifForm.getAttachmentFile();
 473  0
         Attachment attachment = null;
 474  0
         if (attachmentFile != null && !StringUtils.isBlank(attachmentFile.getOriginalFilename())) {
 475  0
             if (attachmentFile.getSize() == 0) {
 476  0
                 GlobalVariables.getMessageMap().putError(String.format("%s.%s",
 477  
                         KRADConstants.NEW_DOCUMENT_NOTE_PROPERTY_NAME,
 478  
                         KRADConstants.NOTE_ATTACHMENT_FILE_PROPERTY_NAME), RiceKeyConstants.ERROR_UPLOADFILE_EMPTY,
 479  
                         attachmentFile.getOriginalFilename());
 480  
             } else {
 481  0
                 if (newNote.getAttachment() != null) {
 482  0
                     attachmentTypeCode = newNote.getAttachment().getAttachmentTypeCode();
 483  
                 }
 484  
 
 485  0
                 DocumentAuthorizer documentAuthorizer =
 486  
                         KRADServiceLocatorWeb.getDocumentHelperService().getDocumentAuthorizer(document);
 487  0
                 if (!documentAuthorizer.canAddNoteAttachment(document, attachmentTypeCode,
 488  
                         GlobalVariables.getUserSession().getPerson())) {
 489  0
                     throw buildAuthorizationException("annotate", document);
 490  
                 }
 491  
                 try {
 492  0
                     String attachmentType = null;
 493  0
                     Attachment newAttachment = newNote.getAttachment();
 494  0
                     if (newAttachment != null) {
 495  0
                         attachmentType = newAttachment.getAttachmentTypeCode();
 496  
                     }
 497  0
                     attachment = getAttachmentService().createAttachment(document.getNoteTarget(),
 498  
                             attachmentFile.getOriginalFilename(), attachmentFile.getContentType(),
 499  
                             (int) attachmentFile.getSize(), attachmentFile.getInputStream(), attachmentType);
 500  0
                 } catch (IOException e) {
 501  0
                     e.printStackTrace();
 502  0
                 }
 503  
             }
 504  
         }
 505  
 
 506  0
         Person kualiUser = GlobalVariables.getUserSession().getPerson();
 507  0
         if (kualiUser == null) {
 508  0
             throw new IllegalStateException("Current UserSession has a null Person.");
 509  
         }
 510  
 
 511  0
         newNote.setAuthorUniversalIdentifier(kualiUser.getPrincipalId());
 512  
 
 513  
         // validate the note
 514  0
         boolean rulePassed = KRADServiceLocatorWeb.getKualiRuleService().applyRules(new AddNoteEvent(document,
 515  
                 newNote));
 516  
 
 517  
         // if the rule evaluation passed, let's add the note
 518  0
         if (rulePassed) {
 519  0
             newNote.refresh();
 520  
 
 521  0
             DocumentHeader documentHeader = document.getDocumentHeader();
 522  
 
 523  
             // adding the attachment after refresh gets called, since the attachment record doesn't get persisted
 524  
             // until the note does (and therefore refresh doesn't have any attachment to autoload based on the id, nor does it
 525  
             // autopopulate the id since the note hasn't been persisted yet)
 526  0
             if (attachment != null) {
 527  0
                 newNote.addAttachment(attachment);
 528  
             }
 529  
             // Save the note if the document is already saved
 530  0
             if (!documentHeader.getWorkflowDocument().isInitiated() && StringUtils.isNotEmpty(
 531  
                     document.getNoteTarget().getObjectId()) && !(document instanceof MaintenanceDocument && NoteType
 532  
                     .BUSINESS_OBJECT.getCode().equals(newNote.getNoteTypeCode()))) {
 533  
 
 534  0
                 getNoteService().save(newNote);
 535  
             }
 536  
 
 537  
         }
 538  
 
 539  0
         return addLine(uifForm, result, request, response);
 540  
     }
 541  
 
 542  
     /**
 543  
      * Called by the delete note action for deleting a note.
 544  
      * Calls the UifControllerBase.deleteLine method to handle
 545  
      * generic actions.
 546  
      */
 547  
     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=deleteNote")
 548  
     public ModelAndView deleteNote(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
 549  
             HttpServletRequest request, HttpServletResponse response) {
 550  
 
 551  0
         String selectedLineIndex = uifForm.getActionParamaterValue("selectedLineIndex");
 552  0
         Document document = ((DocumentFormBase) uifForm).getDocument();
 553  0
         Note note = document.getNote(Integer.parseInt(selectedLineIndex));
 554  
 
 555  0
         Attachment attachment = note.getAttachment();
 556  0
         String attachmentTypeCode = null;
 557  0
         if (attachment != null) {
 558  0
             attachmentTypeCode = attachment.getAttachmentTypeCode();
 559  
         }
 560  
 
 561  0
         String authorUniversalIdentifier = note.getAuthorUniversalIdentifier();
 562  0
         if (!KRADUtils.canDeleteNoteAttachment(document, attachmentTypeCode, authorUniversalIdentifier)) {
 563  0
             throw buildAuthorizationException("annotate", document);
 564  
         }
 565  
 
 566  0
         if (attachment != null && attachment.isComplete()) { // only do this if the note has been persisted
 567  
             //KFSMI-798 - refresh() changed to refreshNonUpdateableReferences()
 568  
             //All references for the business object Attachment are auto-update="none",
 569  
             //so refreshNonUpdateableReferences() should work the same as refresh()
 570  0
             if (note.getNoteIdentifier()
 571  
                     != null) { // KULRICE-2343 don't blow away note reference if the note wasn't persisted
 572  0
                 attachment.refreshNonUpdateableReferences();
 573  
             }
 574  0
             getAttachmentService().deleteAttachmentContents(attachment);
 575  
         }
 576  
         // delete the note if the document is already saved
 577  0
         if (!document.getDocumentHeader().getWorkflowDocument().isInitiated()) {
 578  0
             getNoteService().deleteNote(note);
 579  
         }
 580  
 
 581  0
         return deleteLine(uifForm, result, request, response);
 582  
     }
 583  
 
 584  
     /**
 585  
      * Called by the download attachment action on a note. Method
 586  
      * gets the attachment input stream from the AttachmentService
 587  
      * and writes it to the request output stream.
 588  
      */
 589  
     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=downloadAttachment")
 590  
     public ModelAndView downloadAttachment(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
 591  
             HttpServletRequest request,
 592  
             HttpServletResponse response) throws ServletRequestBindingException, FileNotFoundException, IOException {
 593  
         // Get the attachment input stream
 594  0
         String selectedLineIndex = uifForm.getActionParamaterValue("selectedLineIndex");
 595  0
         Note note = ((DocumentFormBase) uifForm).getDocument().getNote(Integer.parseInt(selectedLineIndex));
 596  0
         Attachment attachment = note.getAttachment();
 597  0
         InputStream is = getAttachmentService().retrieveAttachmentContents(attachment);
 598  
 
 599  
         // Set the response headers
 600  0
         response.setContentType(attachment.getAttachmentMimeTypeCode());
 601  0
         response.setContentLength(attachment.getAttachmentFileSize().intValue());
 602  0
         response.setHeader("Expires", "0");
 603  0
         response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
 604  0
         response.setHeader("Pragma", "public");
 605  0
         response.setHeader("Content-Disposition",
 606  
                 "attachment; filename=\"" + attachment.getAttachmentFileName() + "\"");
 607  
 
 608  
         // Copy the input stream to the response
 609  0
         FileCopyUtils.copy(is, response.getOutputStream());
 610  0
         return null;
 611  
     }
 612  
 
 613  
     /**
 614  
      * Called by the cancel attachment action on a note. Method
 615  
      * removes the attachment file from the form.
 616  
      */
 617  
     @RequestMapping(method = RequestMethod.POST, params = "methodToCall=cancelAttachment")
 618  
     public ModelAndView cancelAttachment(@ModelAttribute("KualiForm") UifFormBase uifForm, BindingResult result,
 619  
             HttpServletRequest request, HttpServletResponse response) {
 620  
         // Remove the attached file
 621  0
         uifForm.setAttachmentFile(null);
 622  0
         return getUIFModelAndView(uifForm);
 623  
     }
 624  
 
 625  
     /**
 626  
      * Checks if the given value matches patterns that indicate sensitive data
 627  
      * and if configured to give a warning for sensitive data will prompt the
 628  
      * user to continue.
 629  
      *
 630  
      * @param form
 631  
      * @param request
 632  
      * @param response
 633  
      * @param fieldName - name of field with value being checked
 634  
      * @param fieldValue - value to check for sensitive data
 635  
      * @param caller - method that should be called back from question
 636  
      * @param context - additional context that needs to be passed back with the
 637  
      * question response
 638  
      * @return - view for spring to forward to, or null if processing should
 639  
      *         continue
 640  
      * @throws Exception
 641  
      */
 642  
     protected String checkAndWarnAboutSensitiveData(DocumentFormBase form, HttpServletRequest request,
 643  
             HttpServletResponse response, String fieldName, String fieldValue, String caller,
 644  
             String context) throws Exception {
 645  
 
 646  0
         String viewName = null;
 647  0
         Document document = form.getDocument();
 648  
 
 649  
         // TODO: need to move containsSensitiveDataPatternMatch to util class in krad
 650  0
         boolean containsSensitiveData = false;
 651  
         //boolean containsSensitiveData = WebUtils.containsSensitiveDataPatternMatch(fieldValue);
 652  
 
 653  
         // check if warning is configured in which case we will prompt, or if
 654  
         // not business rules will thrown an error
 655  0
         boolean warnForSensitiveData = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(
 656  
                 KRADConstants.KRAD_NAMESPACE, ParameterConstants.ALL_COMPONENT,
 657  
                 KRADConstants.SystemGroupParameterNames.SENSITIVE_DATA_PATTERNS_WARNING_IND);
 658  
 
 659  
         // determine if the question has been asked yet
 660  0
         Map<String, String> ticketContext = new HashMap<String, String>();
 661  0
         ticketContext.put(KRADPropertyConstants.DOCUMENT_NUMBER, document.getDocumentNumber());
 662  0
         ticketContext.put(KRADConstants.CALLING_METHOD, caller);
 663  0
         ticketContext.put(KRADPropertyConstants.NAME, fieldName);
 664  
 
 665  0
         boolean questionAsked = GlobalVariables.getUserSession().hasMatchingSessionTicket(
 666  
                 KRADConstants.SENSITIVE_DATA_QUESTION_SESSION_TICKET, ticketContext);
 667  
 
 668  
         // start in logic for confirming the sensitive data
 669  0
         if (containsSensitiveData && warnForSensitiveData && !questionAsked) {
 670  0
             Object question = request.getParameter(KRADConstants.QUESTION_INST_ATTRIBUTE_NAME);
 671  0
             if (question == null || !KRADConstants.DOCUMENT_SENSITIVE_DATA_QUESTION.equals(question)) {
 672  
 
 673  
                 // TODO not ready for question framework yet
 674  
                 /*
 675  
                      * // question hasn't been asked, prompt to continue return
 676  
                      * this.performQuestionWithoutInput(mapping, form, request,
 677  
                      * response, KRADConstants.DOCUMENT_SENSITIVE_DATA_QUESTION,
 678  
                      * getKualiConfigurationService()
 679  
                      * .getPropertyValueAsString(RiceKeyConstants
 680  
                      * .QUESTION_SENSITIVE_DATA_DOCUMENT),
 681  
                      * KRADConstants.CONFIRMATION_QUESTION, caller, context);
 682  
                      */
 683  0
                 viewName = "ask_user_questions";
 684  
             } else {
 685  0
                 Object buttonClicked = request.getParameter(KRADConstants.QUESTION_CLICKED_BUTTON);
 686  
 
 687  
                 // if no button clicked just reload the doc
 688  0
                 if (ConfirmationQuestion.NO.equals(buttonClicked)) {
 689  
                     // TODO figure out what to return
 690  0
                     viewName = "user_says_no";
 691  
                 }
 692  
 
 693  
                 // answered yes, create session ticket so we not to ask question
 694  
                 // again if there are further question requests
 695  0
                 SessionTicket ticket = new SessionTicket(KRADConstants.SENSITIVE_DATA_QUESTION_SESSION_TICKET);
 696  0
                 ticket.setTicketContext(ticketContext);
 697  0
                 GlobalVariables.getUserSession().putSessionTicket(ticket);
 698  
             }
 699  
         }
 700  
 
 701  
         // returning null will indicate processing should continue (no redirect)
 702  0
         return viewName;
 703  
     }
 704  
 
 705  
     /**
 706  
      * Convenience method to combine the two lists of ad hoc recipients into one which should be done before
 707  
      * calling any of the document service methods that expect a list of ad hoc recipients
 708  
      *
 709  
      * @param form - document form instance containing the ad hod lists
 710  
      * @return List<AdHocRouteRecipient> combined ad hoc recipients
 711  
      */
 712  
     protected List<AdHocRouteRecipient> combineAdHocRecipients(DocumentFormBase form) {
 713  0
         Document document = form.getDocument();
 714  
 
 715  0
         List<AdHocRouteRecipient> adHocRecipients = new ArrayList<AdHocRouteRecipient>();
 716  0
         adHocRecipients.addAll(document.getAdHocRoutePersons());
 717  0
         adHocRecipients.addAll(document.getAdHocRouteWorkgroups());
 718  
 
 719  0
         return adHocRecipients;
 720  
     }
 721  
 
 722  
     /**
 723  
      * Convenience method for building authorization exceptions
 724  
      *
 725  
      * @param action - the action that was requested
 726  
      * @param document - document instance the action was requested for
 727  
      */
 728  
     protected DocumentAuthorizationException buildAuthorizationException(String action, Document document) {
 729  0
         return new DocumentAuthorizationException(GlobalVariables.getUserSession().getPerson().getPrincipalName(),
 730  
                 action, document.getDocumentNumber());
 731  
     }
 732  
 
 733  
     public BusinessObjectService getBusinessObjectService() {
 734  0
         if (this.businessObjectService == null) {
 735  0
             this.businessObjectService = KRADServiceLocator.getBusinessObjectService();
 736  
         }
 737  0
         return this.businessObjectService;
 738  
     }
 739  
 
 740  
     public void setBusinessObjectService(BusinessObjectService businessObjectService) {
 741  0
         this.businessObjectService = businessObjectService;
 742  0
     }
 743  
 
 744  
     public DataDictionaryService getDataDictionaryService() {
 745  0
         if (this.dataDictionaryService == null) {
 746  0
             this.dataDictionaryService = KRADServiceLocatorWeb.getDataDictionaryService();
 747  
         }
 748  0
         return this.dataDictionaryService;
 749  
     }
 750  
 
 751  
     public void setDataDictionaryService(DataDictionaryService dataDictionaryService) {
 752  0
         this.dataDictionaryService = dataDictionaryService;
 753  0
     }
 754  
 
 755  
     public DocumentService getDocumentService() {
 756  0
         if (this.documentService == null) {
 757  0
             this.documentService = KRADServiceLocatorWeb.getDocumentService();
 758  
         }
 759  0
         return this.documentService;
 760  
     }
 761  
 
 762  
     public void setDocumentService(DocumentService documentService) {
 763  0
         this.documentService = documentService;
 764  0
     }
 765  
 
 766  
     public DocumentHelperService getDocumentHelperService() {
 767  0
         if (this.documentHelperService == null) {
 768  0
             this.documentHelperService = KRADServiceLocatorWeb.getDocumentHelperService();
 769  
         }
 770  0
         return this.documentHelperService;
 771  
     }
 772  
 
 773  
     public void setDocumentHelperService(DocumentHelperService documentHelperService) {
 774  0
         this.documentHelperService = documentHelperService;
 775  0
     }
 776  
 
 777  
     public AttachmentService getAttachmentService() {
 778  0
         if (attachmentService == null) {
 779  0
             attachmentService = KRADServiceLocator.getAttachmentService();
 780  
         }
 781  0
         return this.attachmentService;
 782  
     }
 783  
 
 784  
     public NoteService getNoteService() {
 785  0
         if (noteService == null) {
 786  0
             noteService = KRADServiceLocator.getNoteService();
 787  
         }
 788  0
         return this.noteService;
 789  
     }
 790  
 
 791  
     public ConfigurationService getConfigurationService() {
 792  0
         return KRADServiceLocator.getKualiConfigurationService();
 793  
     }
 794  
 }