View Javadoc
1   /**
2    * Copyright 2005-2015 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.kns.web.struts.form;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.apache.struts.action.ActionErrors;
20  import org.apache.struts.action.ActionMapping;
21  import org.apache.struts.upload.FormFile;
22  import org.kuali.rice.core.api.CoreApiServiceLocator;
23  import org.kuali.rice.core.api.util.RiceKeyConstants;
24  import org.kuali.rice.core.web.format.NoOpStringFormatter;
25  import org.kuali.rice.core.web.format.TimestampAMPMFormatter;
26  import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
27  import org.kuali.rice.kew.api.KewApiServiceLocator;
28  import org.kuali.rice.kew.api.WorkflowDocument;
29  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
30  import org.kuali.rice.kew.api.action.ActionRequest;
31  import org.kuali.rice.kew.api.action.ActionRequestType;
32  import org.kuali.rice.kew.api.doctype.DocumentType;
33  import org.kuali.rice.kew.api.document.DocumentStatus;
34  import org.kuali.rice.kew.api.document.node.RouteNodeInstance;
35  import org.kuali.rice.kew.api.exception.WorkflowException;
36  import org.kuali.rice.kim.api.KimConstants;
37  import org.kuali.rice.kim.api.identity.Person;
38  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
39  import org.kuali.rice.kns.datadictionary.HeaderNavigation;
40  import org.kuali.rice.kns.datadictionary.KNSDocumentEntry;
41  import org.kuali.rice.kns.util.WebUtils;
42  import org.kuali.rice.kns.web.derivedvaluesetter.DerivedValuesSetter;
43  import org.kuali.rice.krad.UserSessionUtils;
44  import org.kuali.rice.kns.web.ui.HeaderField;
45  import org.kuali.rice.krad.bo.AdHocRoutePerson;
46  import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
47  import org.kuali.rice.krad.bo.Note;
48  import org.kuali.rice.krad.datadictionary.DataDictionary;
49  import org.kuali.rice.krad.document.Document;
50  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
51  import org.kuali.rice.krad.service.ModuleService;
52  import org.kuali.rice.krad.util.GlobalVariables;
53  import org.kuali.rice.krad.util.KRADConstants;
54  import org.kuali.rice.krad.util.MessageMap;
55  import org.kuali.rice.krad.util.ObjectUtils;
56  import org.kuali.rice.krad.util.UrlFactory;
57  import org.springframework.util.AutoPopulatingList;
58  
59  import javax.servlet.http.HttpServletRequest;
60  import java.io.Serializable;
61  import java.util.ArrayList;
62  import java.util.HashMap;
63  import java.util.List;
64  import java.util.Map;
65  import java.util.Properties;
66  
67  /**
68   * TODO we should not be referencing kew constants from this class and wedding ourselves to that workflow application This class is
69   * the base action form for all documents.
70   *
71   * @deprecated Use {@link org.kuali.rice.krad.web.form.DocumentFormBase}.
72   */
73  @Deprecated
74  public abstract class KualiDocumentFormBase extends KualiForm implements Serializable {
75      private static final long serialVersionUID = 916061016201941821L;
76  
77  	private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiDocumentFormBase.class);
78  
79      private Document document;
80      private String annotation = "";
81      private String command;
82  
83      private String docId;
84      private String docTypeName;
85  
86      private List<String> additionalScriptFiles;
87  
88      private AdHocRoutePerson newAdHocRoutePerson;
89      private AdHocRouteWorkgroup newAdHocRouteWorkgroup;
90  
91      private Note newNote;
92      
93      //TODO: is this still needed? I think it's obsolete now
94      private List boNotes;
95      
96      protected FormFile attachmentFile = new BlankFormFile();
97  
98      protected Map editingMode;
99      protected Map documentActions;
100     protected boolean suppressAllButtons;
101     
102     protected Map adHocActionRequestCodes;
103     private boolean returnToActionList;
104 
105     // for session enhancement
106     private String formKey;
107     private String docNum;
108     
109     private List<ActionRequest> actionRequests;
110     private List<String> selectedActionRequests;
111     private String superUserAnnotation;
112     
113     
114     /**
115      * Stores the error map from previous requests, so that we can continue to display error messages displayed during a previous request
116      */
117     private MessageMap errorMapFromPreviousRequest;
118     
119 	/***
120      * @see KualiForm#addRequiredNonEditableProperties()
121      */
122     @Override
123     public void addRequiredNonEditableProperties(){
124     	super.addRequiredNonEditableProperties();
125     	registerRequiredNonEditableProperty(KRADConstants.DOCUMENT_TYPE_NAME);
126     	registerRequiredNonEditableProperty(KRADConstants.FORM_KEY);
127     	registerRequiredNonEditableProperty(KRADConstants.NEW_NOTE_NOTE_TYPE_CODE);
128     }
129 
130 	/**
131 	 * @return the docNum
132 	 */
133 	public String getDocNum() {
134 		return this.docNum;
135 	}
136 
137 	/**
138 	 * @param docNum
139 	 *            the docNum to set
140 	 */
141 	public void setDocNum(String docNum) {
142 		this.docNum = docNum;
143 	}
144     
145     /**
146      * no args constructor that just initializes things for us
147      */
148     @SuppressWarnings("unchecked")
149 	public KualiDocumentFormBase() {
150         super();
151         
152         instantiateDocument();
153         newNote = new Note();
154         this.editingMode = new HashMap();
155         //this.additionalScriptFiles = new AutoPopulatingList(String.class);
156         this.additionalScriptFiles = new AutoPopulatingList<String>(String.class);
157 
158         // set the initial record for persons up
159         newAdHocRoutePerson = new AdHocRoutePerson();
160 
161         // set the initial record for workgroups up
162         newAdHocRouteWorkgroup = new AdHocRouteWorkgroup();
163 
164         // to make sure it posts back the correct time
165         setFormatterType("document.documentHeader.note.finDocNotePostedDttmStamp", TimestampAMPMFormatter.class);
166         setFormatterType("document.documentHeader.note.attachment.finDocNotePostedDttmStamp", TimestampAMPMFormatter.class);
167         //TODO: Chris - Notes: remove the above and change the below from boNotes when notes are finished
168         //overriding note formatter to make sure they post back the full timestamp
169         setFormatterType("document.documentHeader.boNote.notePostedTimestamp",TimestampAMPMFormatter.class);
170         setFormatterType("document.documentBusinessObject.boNote.notePostedTimestamp",TimestampAMPMFormatter.class);
171 
172         setFormatterType("editingMode", NoOpStringFormatter.class);
173         setFormatterType("editableAccounts", NoOpStringFormatter.class);
174 
175         setDocumentActions(new HashMap());
176         suppressAllButtons = false;
177         
178         initializeHeaderNavigationTabs();
179     }
180 
181     /**
182      * Setup workflow doc in the document.
183      */
184     @Override
185     public void populate(HttpServletRequest request) {
186         super.populate(request);
187 
188         WorkflowDocument workflowDocument = null;
189 
190         if (hasDocumentId()) {
191             // populate workflowDocument in documentHeader, if needed
192         	// KULRICE-4444 Obtain Document Header using the Workflow Service to minimize overhead
193             try {
194                 workflowDocument = UserSessionUtils.getWorkflowDocument(GlobalVariables.getUserSession(), getDocument().getDocumentNumber());
195                 if ( workflowDocument == null)
196          	 	{
197                     // gets the workflow document from doc service, doc service will also set the workflow document in the
198                     // user's session
199                     Person person = GlobalVariables.getUserSession().getPerson();
200                     if (ObjectUtils.isNull(person)) {
201                         person = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(KRADConstants.SYSTEM_USER);
202                     }
203          	 		workflowDocument = KRADServiceLocatorWeb.getWorkflowDocumentService().loadWorkflowDocument(getDocument().getDocumentNumber(), person);
204          	 	 	UserSessionUtils.addWorkflowDocument(GlobalVariables.getUserSession(), workflowDocument);
205          	 	 	if (workflowDocument == null)
206          	 	 	{
207          	 	 		throw new WorkflowException("Unable to retrieve workflow document # " + getDocument().getDocumentNumber() + " from workflow document service createWorkflowDocument");
208          	 	 	}
209          	 	 	else
210          	 	 	{
211          	 	 	LOG.debug("Retrieved workflow Document ID: " + workflowDocument.getDocumentId());
212          	 	 	}
213          	 	}
214 
215                 getDocument().getDocumentHeader().setWorkflowDocument(workflowDocument);
216             } catch (WorkflowException e) {
217                 LOG.warn("Error while instantiating workflowDoc", e);
218                 throw new RuntimeException("error populating documentHeader.workflowDocument", e);
219             }
220         } 
221         if (workflowDocument != null) {
222 	        //Populate Document Header attributes
223 	        populateHeaderFields(workflowDocument);
224         }
225     }
226     
227     protected String getPersonInquiryUrlLink(Person user, String linkBody) {
228         StringBuffer urlBuffer = new StringBuffer();
229         
230         if(user != null && StringUtils.isNotEmpty(linkBody) ) {
231         	ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(Person.class);
232         	Map<String, String[]> parameters = new HashMap<String, String[]>();
233         	parameters.put(KimConstants.AttributeConstants.PRINCIPAL_ID, new String[] { user.getPrincipalId() });
234         	String inquiryUrl = moduleService.getExternalizableBusinessObjectInquiryUrl(Person.class, parameters);
235             if(!StringUtils.equals(KimConstants.EntityTypes.SYSTEM, user.getEntityTypeCode())){
236 	            urlBuffer.append("<a href='");
237 	            urlBuffer.append(inquiryUrl);
238 	            urlBuffer.append("' ");
239 	            urlBuffer.append("target='_blank'");
240 	            urlBuffer.append("title='Person Inquiry'>");
241 	            urlBuffer.append(linkBody);
242 	            urlBuffer.append("</a>");
243             } else{
244             	urlBuffer.append(linkBody);
245             }
246         }
247         
248         return urlBuffer.toString();
249     }
250     
251     protected String getDocumentHandlerUrl(String documentId) {
252         Properties parameters = new Properties();
253         parameters.put(KRADConstants.PARAMETER_DOC_ID, documentId);
254         parameters.put(KRADConstants.PARAMETER_COMMAND, KRADConstants.METHOD_DISPLAY_DOC_SEARCH_VIEW);
255         return UrlFactory.parameterizeUrl(
256                 CoreApiServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
257                         KRADConstants.WORKFLOW_URL_KEY) + "/" + KRADConstants.DOC_HANDLER_ACTION, parameters);
258     }
259     
260     protected String buildHtmlLink(String url, String linkBody) {
261         StringBuffer urlBuffer = new StringBuffer();
262         
263         if(StringUtils.isNotEmpty(url) && StringUtils.isNotEmpty(linkBody) ) {
264             urlBuffer.append("<a href='").append(url).append("'>").append(linkBody).append("</a>");
265         }
266         
267         return urlBuffer.toString();
268     }
269     
270     /**
271 	 * This method is used to populate the list of header field objects (see {@link KualiForm#getDocInfo()}) displayed on
272 	 * the Kuali document form display pages.
273 	 * 
274 	 * @param workflowDocument - the workflow document of the document being displayed (null is allowed)
275 	 */
276 	public void populateHeaderFields(WorkflowDocument workflowDocument) {
277 		getDocInfo().clear();
278 		getDocInfo().addAll(getStandardHeaderFields(workflowDocument));
279 	}
280 
281 	/**
282 	 * This method returns a list of {@link HeaderField} objects that are used by default on Kuali document display pages. To
283 	 * use this list and override an individual {@link HeaderField} object the id constants from
284 	 * {@link org.kuali.rice.krad.util.KRADConstants.DocumentFormHeaderFieldIds} can be used to identify items from the list.
285 	 * 
286 	 * @param workflowDocument - the workflow document of the document being displayed (null is allowed)
287 	 * @return a list of the standard fields displayed by default for all Kuali documents
288 	 */
289     protected List<HeaderField> getStandardHeaderFields(WorkflowDocument workflowDocument) {
290     	List<HeaderField> headerFields = new ArrayList<HeaderField>();
291     	setNumColumns(2);
292     	// check for a document template number as that will dictate column numbering
293     	HeaderField docTemplateNumber = null;
294         if ((ObjectUtils.isNotNull(getDocument())) && (ObjectUtils.isNotNull(getDocument().getDocumentHeader())) && (StringUtils.isNotBlank(getDocument().getDocumentHeader().getDocumentTemplateNumber()))) {
295 			String templateDocumentNumber = getDocument().getDocumentHeader().getDocumentTemplateNumber();
296 			docTemplateNumber = new HeaderField(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_TEMPLATE_NUMBER, "DataDictionary.DocumentHeader.attributes.documentTemplateNumber",
297 					templateDocumentNumber,	buildHtmlLink(getDocumentHandlerUrl(templateDocumentNumber), templateDocumentNumber));
298 		}
299         //Document Number    	
300         HeaderField docNumber = new HeaderField("DataDictionary.DocumentHeader.attributes.documentNumber", workflowDocument != null? getDocument().getDocumentNumber() : null);
301         docNumber.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_NUMBER);
302         HeaderField docStatus = new HeaderField("DataDictionary.AttributeReference.attributes.workflowDocumentStatus", workflowDocument != null? workflowDocument.getStatus().getLabel() : null);
303         docStatus.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_WORKFLOW_STATUS);
304         String initiatorNetworkId = null;
305         Person user = null;
306     	if (workflowDocument != null) {
307        		if (getInitiator() == null) {
308     			LOG.warn("User Not Found while attempting to build inquiry link for document header fields");
309     		} else {
310     			user = getInitiator();
311     			initiatorNetworkId = getInitiator().getPrincipalName();
312     		}
313     	}
314         String inquiryUrl = getPersonInquiryUrlLink(user, workflowDocument != null? initiatorNetworkId:null);
315 
316         HeaderField docInitiator = new HeaderField(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_INITIATOR, "DataDictionary.AttributeReference.attributes.initiatorNetworkId",
317         workflowDocument != null? initiatorNetworkId : null, workflowDocument != null? inquiryUrl : null);
318         
319         String createDateStr = null;
320         if(workflowDocument != null && workflowDocument.getDateCreated() != null) {
321             createDateStr = CoreApiServiceLocator.getDateTimeService().toString(workflowDocument.getDateCreated().toDate(), "hh:mm a MM/dd/yyyy");
322         }
323         
324         HeaderField docCreateDate = new HeaderField("DataDictionary.AttributeReference.attributes.createDate", createDateStr);
325         docCreateDate.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_CREATE_DATE);
326         if (ObjectUtils.isNotNull(docTemplateNumber)) {
327         	setNumColumns(3);
328         }
329         
330         headerFields.add(docNumber);
331         headerFields.add(docStatus);
332         if (ObjectUtils.isNotNull(docTemplateNumber)) {
333         	headerFields.add(docTemplateNumber);
334         }
335         headerFields.add(docInitiator);
336         headerFields.add(docCreateDate);
337         if (ObjectUtils.isNotNull(docTemplateNumber)) {
338         	// adding an empty field so implementors do not have to worry about additional fields being put on the wrong row
339         	headerFields.add(HeaderField.EMPTY_FIELD);
340         }
341     	return headerFields;
342     }    
343 
344     /**
345      * @see org.apache.struts.action.ActionForm#validate(org.apache.struts.action.ActionMapping,
346      *      javax.servlet.http.HttpServletRequest)
347      */
348     @Override
349     public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
350         // check that annotation does not exceed 2000 characters
351         setAnnotation(StringUtils.stripToNull(getAnnotation()));
352         int diff = StringUtils.defaultString(getAnnotation()).length() - KRADConstants.DOCUMENT_ANNOTATION_MAX_LENGTH;
353         if (diff > 0) {
354             GlobalVariables.getMessageMap().putError("annotation", RiceKeyConstants.ERROR_DOCUMENT_ANNOTATION_MAX_LENGTH_EXCEEDED, new String[] { Integer.toString(KRADConstants.DOCUMENT_ANNOTATION_MAX_LENGTH), Integer.toString(diff) });
355         }
356         return super.validate(mapping, request);
357     }
358 
359     /**
360      * @return true if this document was properly initialized with a DocumentHeader and related KualiWorkflowDocument
361      */
362     final public boolean isFormDocumentInitialized() {
363         boolean initialized = false;
364 
365         if (document != null) {
366             if (document.getDocumentHeader() != null) {
367                 initialized = document.getDocumentHeader().hasWorkflowDocument();
368             }
369         }
370 
371         return initialized;
372     }
373 
374 
375     /**
376      * @return Map of editingModes for this document, as set during the most recent call to
377      *         populate(javax.servlet.http.HttpServletRequest)
378      */
379     @SuppressWarnings("unchecked")
380 	public Map getEditingMode() {
381         return editingMode;
382     }
383 
384     /**
385      * Set editingMode for this document
386      */
387     @SuppressWarnings("unchecked")
388 	public void setEditingMode(Map editingMode) {
389         this.editingMode = editingMode;
390     }
391     
392     /**
393 	 * @return the documentActions
394 	 */
395 	@SuppressWarnings("unchecked")
396 	public Map getDocumentActions() {
397 		return this.documentActions;
398 	}
399 
400 	/**
401 	 * @param documentActions the documentActions to set
402 	 */
403 	@SuppressWarnings("unchecked")
404 	public void setDocumentActions(Map documentActions) {
405 		this.documentActions = documentActions;
406 	}
407 	
408 	
409 
410 	/**
411 	 * @param adHocActionRequestCodes the adHocActionRequestCodes to set
412 	 */
413 	@SuppressWarnings("unchecked")
414 	public void setAdHocActionRequestCodes(Map adHocActionRequestCodes) {
415 		this.adHocActionRequestCodes = adHocActionRequestCodes;
416 	}
417 
418 	/**
419      * @return a map of the possible action request codes that takes into account the users context on the document
420      */
421     @SuppressWarnings("unchecked")
422 	public Map getAdHocActionRequestCodes() {
423         //Map adHocActionRequestCodes = new HashMap();
424         //KRADServiceLocatorInternal.getDocumentHelperService()
425         /*if (getWorkflowDocument() != null) {
426             if (getWorkflowDocument().isFYIRequested()) {
427                 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL);
428             }
429             else if (getWorkflowDocument().isAcknowledgeRequested()) {
430                 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ_LABEL);
431                 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL);
432             }
433             else if (getWorkflowDocument().isApprovalRequested() || getWorkflowDocument().isCompletionRequested() || getWorkflowDocument().stateIsInitiated() || getWorkflowDocument().stateIsSaved()) {
434                 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ_LABEL);
435                 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL);
436                 adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, KewApiConstants.ACTION_REQUEST_APPROVE_REQ_LABEL);
437             }
438         }*/
439         return adHocActionRequestCodes;
440     }
441 
442 
443     /**
444      * @return the list of ad hoc routing persons
445      */
446     public List<AdHocRoutePerson> getAdHocRoutePersons() {
447         return document.getAdHocRoutePersons();
448     }
449 
450 
451     /**
452      * @return attachmentFile
453      */
454     public FormFile getAttachmentFile() {
455         return attachmentFile;
456     }
457 
458     /**
459      * @param attachmentFile The attachmentFile to set.
460      */
461     public void setAttachmentFile(FormFile attachmentFile) {
462         this.attachmentFile = attachmentFile;
463     }
464 
465 
466     /**
467      * set the ad hoc routing persons list
468      *
469      * @param adHocRouteRecipients
470      */
471     public void setAdHocRoutePersons(List<AdHocRoutePerson> adHocRouteRecipients) {
472         document.setAdHocRoutePersons(adHocRouteRecipients);
473     }
474 
475     /**
476      * get the ad hoc routing workgroup requests
477      *
478      * @return
479      */
480     public List<AdHocRouteWorkgroup> getAdHocRouteWorkgroups() {
481         return document.getAdHocRouteWorkgroups();
482     }
483 
484     /**
485      * set the ad hoc routing workgroup requests
486      *
487      * @param adHocRouteWorkgroups
488      */
489     public void setAdHocRouteWorkgroups(List<AdHocRouteWorkgroup> adHocRouteWorkgroups) {
490         document.setAdHocRouteWorkgroups(adHocRouteWorkgroups);
491     }
492 
493     /**
494      * Special getter based on index to work with multi rows for ad hoc routing to persons struts page
495      *
496      * @param index
497      * @return
498      */
499     public AdHocRoutePerson getAdHocRoutePerson(int index) {
500         while (getAdHocRoutePersons().size() <= index) {
501             getAdHocRoutePersons().add(new AdHocRoutePerson());
502         }
503         return getAdHocRoutePersons().get(index);
504     }
505 
506     /**
507      * Special getter based on index to work with multi rows for ad hoc routing to workgroups struts page
508      *
509      * @param index
510      * @return
511      */
512     public AdHocRouteWorkgroup getAdHocRouteWorkgroup(int index) {
513         while (getAdHocRouteWorkgroups().size() <= index) {
514             getAdHocRouteWorkgroups().add(new AdHocRouteWorkgroup());
515         }
516         return getAdHocRouteWorkgroups().get(index);
517     }
518 
519     /**
520      * @return the new ad hoc route person object
521      */
522     public AdHocRoutePerson getNewAdHocRoutePerson() {
523         return newAdHocRoutePerson;
524     }
525 
526     /**
527      * set the new ad hoc route person object
528      *
529      * @param newAdHocRoutePerson
530      */
531     public void setNewAdHocRoutePerson(AdHocRoutePerson newAdHocRoutePerson) {
532         this.newAdHocRoutePerson = newAdHocRoutePerson;
533     }
534 
535     /**
536      * @return the new ad hoc route workgroup object
537      */
538     public AdHocRouteWorkgroup getNewAdHocRouteWorkgroup() {
539         return newAdHocRouteWorkgroup;
540     }
541 
542     /**
543      * set the new ad hoc route workgroup object
544      *
545      * @param newAdHocRouteWorkgroup
546      */
547     public void setNewAdHocRouteWorkgroup(AdHocRouteWorkgroup newAdHocRouteWorkgroup) {
548         this.newAdHocRouteWorkgroup = newAdHocRouteWorkgroup;
549     }
550 
551     /**
552      * @return Returns the Document
553      */
554     public Document getDocument() {
555         return document;
556     }
557 
558     /**
559      * @param document
560      */
561     public void setDocument(Document document) {
562         this.document = document;
563         if(document != null && StringUtils.isNotEmpty(document.getDocumentNumber())) {
564             populateHeaderFields(document.getDocumentHeader().getWorkflowDocument());
565         }
566     }
567 
568     /**
569      * @return WorkflowDocument for this form's document
570      */
571     public WorkflowDocument getWorkflowDocument() {
572         return getDocument().getDocumentHeader().getWorkflowDocument();
573     }
574     
575     /**
576 	 *  Null-safe check to see if the workflow document object exists before attempting to retrieve it.
577      *  (Which, if called, will throw an exception.)
578 	 */
579     public boolean isHasWorkflowDocument() {
580     	if ( getDocument() == null || getDocument().getDocumentHeader() == null ) {
581     		return false;
582     	}
583     	return getDocument().getDocumentHeader().hasWorkflowDocument();
584     }
585 
586     /**
587      * TODO rk implemented to account for caps coming from kuali user service from workflow
588      */
589     public boolean isUserDocumentInitiator() {
590         if (getWorkflowDocument() != null) {
591             return getWorkflowDocument().getInitiatorPrincipalId().equalsIgnoreCase(
592             		GlobalVariables.getUserSession().getPrincipalId());
593         }
594         return false;
595     }
596 
597     public Person getInitiator() {
598     	String initiatorPrincipalId = getWorkflowDocument().getInitiatorPrincipalId();
599     	return KimApiServiceLocator.getPersonService().getPerson(initiatorPrincipalId);
600     }
601 
602     /**
603      * @return true if the workflowDocument associated with this form is currently enroute
604      */
605     public boolean isDocumentEnRoute() {
606         return getWorkflowDocument().isEnroute();
607     }
608 
609     /**
610      * @param annotation The annotation to set.
611      */
612     public void setAnnotation(String annotation) {
613         this.annotation = annotation;
614     }
615 
616     /**
617      * @return Returns the annotation.
618      */
619     public String getAnnotation() {
620         return annotation;
621     }
622 
623     /**
624      * @return returns the command that was passed from workflow
625      */
626     public String getCommand() {
627         return command;
628     }
629 
630     /**
631      * setter for the command that was passed from workflow on the url
632      *
633      * @param command
634      */
635     public void setCommand(String command) {
636         this.command = command;
637     }
638 
639     /**
640      * @return returns the docId that was passed from workflow on the url
641      */
642     public String getDocId() {
643         return docId;
644     }
645 
646     /**
647      * setter for the docId that was passed from workflow on the url
648      *
649      * @param docId
650      */
651     public void setDocId(String docId) {
652         this.docId = docId;
653     }
654 
655     /**
656      * getter for the docTypeName that was passed from workflow on the url
657      *
658      * @return
659      */
660     public String getDocTypeName() {
661         return docTypeName;
662     }
663 
664     /**
665      * setter for the docTypeName that was passed from workflow on the url
666      *
667      * @param docTypeName
668      */
669     public void setDocTypeName(String docTypeName) {
670         this.docTypeName = docTypeName;
671     }
672 
673     /**
674      * getter for convenience that will return the initiators network id
675      *
676      * @return
677      */
678     public String getInitiatorNetworkId() {
679         return this.getWorkflowDocument().getInitiatorPrincipalId();
680     }
681 
682     /**
683      * Gets the suppressAllButtons attribute.
684      *
685      * @return Returns the suppressAllButtons.
686      */
687     public final boolean isSuppressAllButtons() {
688         return suppressAllButtons;
689     }
690 
691     /**
692      * Sets the suppressAllButtons attribute value.
693      *
694      * @param suppressAllButtons The suppressAllButtons to set.
695      */
696     public final void setSuppressAllButtons(boolean suppressAllButtons) {
697         this.suppressAllButtons = suppressAllButtons;
698     }
699 
700     /**
701      * @return true if this form's getDocument() method returns a Document, and if that Document's getDocumentHeaderId method
702      *         returns a non-null
703      */
704     public boolean hasDocumentId() {
705         boolean hasDocId = false;
706 
707         Document d = getDocument();
708         if (d != null) {
709             String docHeaderId = d.getDocumentNumber();
710 
711             hasDocId = StringUtils.isNotBlank(docHeaderId);
712         }
713 
714         return hasDocId;
715     }
716 
717     /**
718      * Sets flag indicating whether upon completion of approve, blanketApprove, cancel, or disapprove, the user should be returned
719      * to the actionList instead of to the portal
720      *
721      * @param returnToActionList
722      */
723     public void setReturnToActionList(boolean returnToActionList) {
724         this.returnToActionList = returnToActionList;
725     }
726 
727     public boolean isReturnToActionList() {
728         return returnToActionList;
729     }
730 
731     public List<String> getAdditionalScriptFiles() {
732         return additionalScriptFiles;
733     }
734 
735     public void setAdditionalScriptFiles(List<String> additionalScriptFiles) {
736         this.additionalScriptFiles = additionalScriptFiles;
737     }
738 
739     public void setAdditionalScriptFile( int index, String scriptFile ) {
740         additionalScriptFiles.set( index, scriptFile );
741 	}
742 
743     public String getAdditionalScriptFile( int index ) {
744         return additionalScriptFiles.get( index );
745     }
746 
747     public Note getNewNote() {
748         return newNote;
749     }
750 
751     public void setNewNote(Note newNote) {
752         this.newNote = newNote;
753     }
754 
755     /**
756      * Gets the boNotes attribute. 
757      * @return Returns the boNotes.
758      */
759     @SuppressWarnings("unchecked")
760 	public List getBoNotes() {
761         return boNotes;
762     }
763 
764     /**
765      * Sets the boNotes attribute value.
766      * @param boNotes The boNotes to set.
767      */
768     @SuppressWarnings("unchecked")
769 	public void setBoNotes(List boNotes) {
770         this.boNotes = boNotes;
771     }
772 
773     public String getFormKey() {
774         return this.formKey;
775     }
776 
777     public void setFormKey(String formKey) {
778         this.formKey = formKey;
779     }
780 
781     /* Reset method
782      * This is initially created for session document implementation
783      * @param mapping
784      * @param request
785      */
786     @Override
787     public void reset(ActionMapping mapping, HttpServletRequest request) {
788     	super.reset(mapping, request);
789         this.setMethodToCall(null);
790         this.setRefreshCaller(null);
791         this.setAnchor(null);
792         this.setCurrentTabIndex(0);
793         this.setSelectedActionRequests(new ArrayList<String>());
794     }
795 
796     
797     /**
798      * Adds the attachment file size to the list of max file sizes.
799      * 
800      * @see org.kuali.rice.krad.web.struts.pojo.PojoFormBase#customInitMaxUploadSizes()
801      */
802     @Override
803     protected void customInitMaxUploadSizes() {
804         super.customInitMaxUploadSizes();
805         String attachmentSize = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KRADConstants.KNS_NAMESPACE, KRADConstants.DetailTypes.DOCUMENT_DETAIL_TYPE, KRADConstants.ATTACHMENT_MAX_FILE_SIZE_PARM_NM);
806         if (StringUtils.isNotBlank(attachmentSize)) {
807             addMaxUploadSize(attachmentSize);
808         }
809     }
810 
811     
812     
813 	/**
814 	 * This overridden method ...
815 	 * IMPORTANT: any overrides of this method must ensure that nothing in the HTTP request will be used to determine whether document is in session 
816 	 * 
817 	 * @see org.kuali.rice.krad.web.struts.pojo.PojoFormBase#shouldPropertyBePopulatedInForm(java.lang.String, javax.servlet.http.HttpServletRequest)
818 	 */
819 	@Override
820 	public boolean shouldPropertyBePopulatedInForm(String requestParameterName, HttpServletRequest request) {
821 		for ( String prefix : KRADConstants.ALWAYS_VALID_PARAMETER_PREFIXES ) {
822 			if (requestParameterName.startsWith(prefix)) {
823 				return true;
824 			}
825 		}
826 
827 		if (StringUtils.equalsIgnoreCase(getMethodToCall(), KRADConstants.DOC_HANDLER_METHOD)) {
828 			return true;
829 		}
830 		if (WebUtils.isDocumentSession(getDocument(), this)) {
831 			return isPropertyEditable(requestParameterName) || isPropertyNonEditableButRequired(requestParameterName);
832 		}
833 		return true;
834 	}
835 
836 	/**
837 	 * This overridden method ...
838 	 * 
839 	 * @see KualiForm#shouldMethodToCallParameterBeUsed(java.lang.String, java.lang.String, javax.servlet.http.HttpServletRequest)
840 	 */
841 	@Override
842 	public boolean shouldMethodToCallParameterBeUsed(
843 			String methodToCallParameterName,
844 			String methodToCallParameterValue, HttpServletRequest request) {
845 		if (StringUtils.equals(methodToCallParameterName, KRADConstants.DISPATCH_REQUEST_PARAMETER) &&
846 				StringUtils.equals(methodToCallParameterValue, KRADConstants.DOC_HANDLER_METHOD)) {
847 			return true;
848 		}
849 		return super.shouldMethodToCallParameterBeUsed(methodToCallParameterName,
850 				methodToCallParameterValue, request);
851 	}
852 	
853 	public MessageMap getMessageMapFromPreviousRequest() {
854 		return this.errorMapFromPreviousRequest;
855 	}
856 	
857 	public void setMessageMapFromPreviousRequest(MessageMap errorMapFromPreviousRequest) {
858 		this.errorMapFromPreviousRequest = errorMapFromPreviousRequest;
859 	}
860 	
861 	@Override
862 	public void setDerivedValuesOnForm(HttpServletRequest request) {
863 		super.setDerivedValuesOnForm(request);
864 
865 		String docTypeName = getDocTypeName();
866 		if (StringUtils.isNotBlank(docTypeName)) {
867 			DataDictionary dataDictionary = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary();
868 
869             Class<? extends DerivedValuesSetter> derivedValuesSetterClass = null;
870             KNSDocumentEntry documentEntry = (KNSDocumentEntry) dataDictionary.getDocumentEntry(docTypeName);
871             derivedValuesSetterClass = (documentEntry).getDerivedValuesSetterClass();
872 
873 			if (derivedValuesSetterClass != null) {
874 				DerivedValuesSetter derivedValuesSetter = null;
875 				try {
876 					derivedValuesSetter = derivedValuesSetterClass.newInstance();
877 				}
878 
879 				catch (Exception e) {
880 					LOG.error("Unable to instantiate class " + derivedValuesSetterClass.getName(), e);
881 					throw new RuntimeException("Unable to instantiate class " + derivedValuesSetterClass.getName(), e);
882 				}
883 				derivedValuesSetter.setDerivedValues(this, request);
884 			}
885 		}
886 	}
887 	
888 	protected String getDefaultDocumentTypeName() {
889 		return "";
890 	}
891 	
892 	/** will instatiate a new document setting it on the form if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value. */
893 	protected void instantiateDocument() {
894 		if (document == null && StringUtils.isNotBlank(getDefaultDocumentTypeName())) {
895 			Class<? extends Document> documentClass = getDocumentClass();
896 			try {
897 				Document document = documentClass.newInstance();
898 				setDocument(document);
899 			} catch (Exception e) {
900 				LOG.error("Unable to instantiate document class " + documentClass.getName() + " document type " + getDefaultDocumentTypeName());
901 				throw new RuntimeException(e);
902 			}
903 		}
904 	}
905 	
906 	/** gets the document class from the datadictionary if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value otherwise behavior is nondeterministic. */
907 	private Class<? extends Document> getDocumentClass() {
908 		return KRADServiceLocatorWeb.getDataDictionaryService().getDocumentClassByTypeName(getDefaultDocumentTypeName());
909 	}
910 	
911 	/**initializes the header tabs from what is defined in the datadictionary if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value. */
912     protected void initializeHeaderNavigationTabs() {
913     	if (StringUtils.isNotBlank(getDefaultDocumentTypeName())) {
914     		final KNSDocumentEntry docEntry = (KNSDocumentEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(getDocumentClass().getName());
915     		final List<HeaderNavigation> navList = docEntry.getHeaderNavigationList();
916     		final HeaderNavigation[] list = new HeaderNavigation[navList.size()];
917     		super.setHeaderNavigationTabs(navList.toArray(list));
918     	}
919     }
920     
921     public List<ActionRequest> getActionRequests() {
922 		return actionRequests;
923 	}
924 
925 	public void setActionRequests(List<ActionRequest> actionRequests) {
926 		this.actionRequests = actionRequests;
927 	}
928 
929 	public List<String> getSelectedActionRequests() {
930 		return selectedActionRequests;
931 	}
932 
933 	public void setSelectedActionRequests(List<String> selectedActionRequests) {
934 		this.selectedActionRequests = selectedActionRequests;
935 	}
936 
937     public List<ActionRequest> getActionRequestsRequiringApproval() {
938         List<ActionRequest> actionRequests = getActionRequests();
939         List<ActionRequest> actionRequestsApprove = new ArrayList<ActionRequest>();;
940 
941         for (ActionRequest actionRequest: actionRequests) {
942             if  ((StringUtils.equals(actionRequest.getActionRequested().getCode(), ActionRequestType.APPROVE.getCode())) ||
943                     (StringUtils.equals(actionRequest.getActionRequested().getCode(), ActionRequestType.COMPLETE.getCode()))) {
944                 actionRequestsApprove.add(actionRequest);
945             }
946         }
947         return actionRequestsApprove;
948     }
949 
950 	public String getSuperUserAnnotation() {
951 		return superUserAnnotation;
952 	}
953 
954 	public void setSuperUserAnnotation(String superUserAnnotation) {
955 		this.superUserAnnotation = superUserAnnotation;
956 	}
957 
958     public boolean isSuperUserActionAvaliable() {
959         List<ActionRequest> actionRequests = getActionRequestsRequiringApproval();
960         boolean hasSingleActionToTake = false;
961         boolean canSuperUserApprove = false;
962         boolean canSuperUserDisapprove = false;
963 
964         hasSingleActionToTake =  ( isSuperUserApproveSingleActionRequestAuthorized() &&
965                 isStateAllowsApproveSingleActionRequest() &&
966                 !actionRequests.isEmpty());
967         if (!hasSingleActionToTake) {
968             canSuperUserApprove = (isSuperUserApproveDocumentAuthorized() && isStateAllowsApproveOrDisapprove());
969         }
970         if (!canSuperUserApprove) {
971             canSuperUserDisapprove = (isSuperUserDisapproveDocumentAuthorized() && isStateAllowsApproveOrDisapprove());
972         }
973 
974         return (hasSingleActionToTake || canSuperUserApprove || canSuperUserDisapprove) ;
975     }
976 
977     public boolean isSuperUserApproveSingleActionRequestAuthorized() {
978         String principalId =  GlobalVariables.getUserSession().getPrincipalId();
979         String docId = this.getDocId();
980         DocumentType documentType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(docTypeName);
981         String docTypeId = null;
982         if (documentType != null) {
983             docTypeId = documentType.getId();
984         }
985         if ( KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, docTypeId) ) {
986             return true;
987         }
988         List<RouteNodeInstance> routeNodeInstances= KewApiServiceLocator.getWorkflowDocumentService().getRouteNodeInstances(docId);
989         String documentStatus =  KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(docId).getCode();
990         return KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveSingleActionRequest(
991                 principalId, getDocTypeName(), routeNodeInstances, documentStatus);
992     }
993 	
994 	public boolean isSuperUserApproveDocumentAuthorized() {
995         String principalId =  GlobalVariables.getUserSession().getPrincipalId();
996         String docId = this.getDocId();
997         DocumentType documentType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(docTypeName);
998         String docTypeId = null;
999         if (documentType != null) {
1000             docTypeId = documentType.getId();
1001         }
1002         if ( KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, docTypeId) ) {
1003             return true;
1004         }
1005 	    List<RouteNodeInstance> routeNodeInstances= KewApiServiceLocator.getWorkflowDocumentService().getRouteNodeInstances(docId);
1006         String documentStatus =  KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(docId).getCode();
1007         return KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveDocument(
1008                     principalId, this.getDocTypeName(), routeNodeInstances, documentStatus);
1009 	}
1010 	
1011 	public boolean isSuperUserDisapproveDocumentAuthorized() {
1012         String principalId =  GlobalVariables.getUserSession().getPrincipalId();
1013         String docId = this.getDocId();
1014         DocumentType documentType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(docTypeName);
1015         String docTypeId = null;
1016         if (documentType != null) {
1017             docTypeId = documentType.getId();
1018         }
1019         if ( KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, docTypeId) ) {
1020             return true;
1021         }
1022 	    List<RouteNodeInstance> routeNodeInstances= KewApiServiceLocator.getWorkflowDocumentService().getRouteNodeInstances(docId);
1023         String documentStatus =  KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(docId).getCode();
1024         return KewApiServiceLocator.getDocumentTypeService().canSuperUserDisapproveDocument(
1025             principalId, this.getDocTypeName(), routeNodeInstances, documentStatus);
1026    	}
1027 
1028     public boolean isSuperUserAuthorized() {
1029         String docId = this.getDocId();
1030         if (StringUtils.isBlank(docId) || ObjectUtils.isNull(docTypeName)) {
1031             return false;
1032         }
1033 
1034         DocumentType documentType = KewApiServiceLocator.getDocumentTypeService().getDocumentTypeByName(docTypeName);
1035         String docTypeId = null;
1036         if (documentType != null) {
1037             docTypeId = documentType.getId();
1038         }
1039         String principalId =  GlobalVariables.getUserSession().getPrincipalId();
1040         if ( KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeId(principalId, docTypeId) ) {
1041             return true;
1042         }
1043         List<RouteNodeInstance> routeNodeInstances= KewApiServiceLocator.getWorkflowDocumentService().getRouteNodeInstances(
1044                 docId);
1045         String documentStatus =  KewApiServiceLocator.getWorkflowDocumentService().getDocumentStatus(docId).getCode();
1046         return ((KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveSingleActionRequest(
1047                     principalId, this.getDocTypeName(), routeNodeInstances, documentStatus)) ||
1048                 (KewApiServiceLocator.getDocumentTypeService().canSuperUserApproveDocument(
1049                     principalId, this.getDocTypeName(), routeNodeInstances, documentStatus)) ||
1050                 (KewApiServiceLocator.getDocumentTypeService().canSuperUserDisapproveDocument (
1051                     principalId, this.getDocTypeName(), routeNodeInstances, documentStatus))) ;
1052     }
1053 	
1054     public boolean isStateAllowsApproveOrDisapprove() {
1055         if(this.getDocument().getDocumentHeader().hasWorkflowDocument()) {
1056             DocumentStatus status = null;
1057             WorkflowDocument document = WorkflowDocumentFactory.loadDocument(GlobalVariables.getUserSession().getPrincipalId(),
1058                 this.getDocument().getDocumentHeader().getWorkflowDocument().getDocumentId());
1059             if (ObjectUtils.isNotNull(document)) {
1060                 status = document.getStatus();
1061             } else {
1062                 status = this.getDocument().getDocumentHeader().getWorkflowDocument().getStatus();
1063             }
1064             return !(isStateProcessedOrDisapproved(status) ||
1065                      isStateInitiatedFinalCancelled(status) ||
1066                      StringUtils.equals(status.getCode(), DocumentStatus.SAVED.getCode()));
1067         } else {
1068             return false;
1069         }
1070     }
1071 
1072     public boolean isStateAllowsApproveSingleActionRequest() {
1073         if(this.getDocument().getDocumentHeader().hasWorkflowDocument()) {
1074             DocumentStatus status = null;
1075             WorkflowDocument document = WorkflowDocumentFactory.loadDocument(GlobalVariables.getUserSession().getPrincipalId(),
1076                     this.getDocument().getDocumentHeader().getWorkflowDocument().getDocumentId());
1077             if (ObjectUtils.isNotNull(document)) {
1078                 status = document.getStatus();
1079             } else {
1080                 status = this.getDocument().getDocumentHeader().getWorkflowDocument().getStatus();
1081             }
1082             return !(isStateInitiatedFinalCancelled(status));
1083         } else {
1084             return false;
1085         }
1086     }
1087 
1088     public boolean isStateProcessedOrDisapproved(DocumentStatus status) {
1089         return (StringUtils.equals(status.getCode(), DocumentStatus.PROCESSED.getCode()) ||
1090                 StringUtils.equals(status.getCode(), DocumentStatus.DISAPPROVED.getCode()));
1091     }
1092 
1093     public boolean isStateInitiatedFinalCancelled(DocumentStatus status) {
1094         return (StringUtils.equals(status.getCode(), DocumentStatus.INITIATED.getCode()) ||
1095                 StringUtils.equals(status.getCode(), DocumentStatus.FINAL.getCode()) ||
1096                 StringUtils.equals(status.getCode(), DocumentStatus.CANCELED.getCode()));
1097     }
1098 }