View Javadoc

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