001    /**
002     * Copyright 2005-2012 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.kns.web.struts.form;
017    
018    import java.io.Serializable;
019    import java.util.ArrayList;
020    import java.util.HashMap;
021    import java.util.List;
022    import java.util.Map;
023    import java.util.Properties;
024    
025    import javax.servlet.http.HttpServletRequest;
026    
027    import org.apache.commons.lang.StringUtils;
028    import org.apache.struts.action.ActionErrors;
029    import org.apache.struts.action.ActionMapping;
030    import org.apache.struts.upload.FormFile;
031    import org.kuali.rice.core.api.CoreApiServiceLocator;
032    import org.kuali.rice.core.api.util.RiceKeyConstants;
033    import org.kuali.rice.core.web.format.NoOpStringFormatter;
034    import org.kuali.rice.core.web.format.TimestampAMPMFormatter;
035    import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator;
036    import org.kuali.rice.kew.api.KewApiServiceLocator;
037    import org.kuali.rice.kew.api.WorkflowDocument;
038    import org.kuali.rice.kew.api.action.ActionRequest;
039    import org.kuali.rice.kew.api.document.DocumentStatus;
040    import org.kuali.rice.kew.api.exception.WorkflowException;
041    import org.kuali.rice.kim.api.KimConstants;
042    import org.kuali.rice.kim.api.identity.Person;
043    import org.kuali.rice.kim.api.services.KimApiServiceLocator;
044    import org.kuali.rice.kns.datadictionary.HeaderNavigation;
045    import org.kuali.rice.kns.datadictionary.KNSDocumentEntry;
046    import org.kuali.rice.kns.util.WebUtils;
047    import org.kuali.rice.kns.web.derivedvaluesetter.DerivedValuesSetter;
048    import org.kuali.rice.kns.web.ui.HeaderField;
049    import org.kuali.rice.krad.bo.AdHocRoutePerson;
050    import org.kuali.rice.krad.bo.AdHocRouteWorkgroup;
051    import org.kuali.rice.krad.bo.Note;
052    import org.kuali.rice.krad.datadictionary.DataDictionary;
053    import org.kuali.rice.krad.document.Document;
054    import org.kuali.rice.krad.service.KRADServiceLocator;
055    import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
056    import org.kuali.rice.krad.service.ModuleService;
057    import org.kuali.rice.krad.service.SessionDocumentService;
058    import org.kuali.rice.krad.util.GlobalVariables;
059    import org.kuali.rice.krad.util.KRADConstants;
060    import org.kuali.rice.krad.util.MessageMap;
061    import org.kuali.rice.krad.util.ObjectUtils;
062    import org.kuali.rice.krad.util.UrlFactory;
063    import org.springframework.util.AutoPopulatingList;
064    
065    /**
066     * TODO we should not be referencing kew constants from this class and wedding ourselves to that workflow application This class is
067     * the base action form for all documents.
068     */
069    public abstract class KualiDocumentFormBase extends KualiForm implements Serializable {
070        private static final long serialVersionUID = 916061016201941821L;
071    
072            private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(KualiDocumentFormBase.class);
073    
074        private Document document;
075        private String annotation = "";
076        private String command;
077    
078        private String docId;
079        private String docTypeName;
080    
081        private List<String> additionalScriptFiles;
082    
083        private AdHocRoutePerson newAdHocRoutePerson;
084        private AdHocRouteWorkgroup newAdHocRouteWorkgroup;
085    
086        private Note newNote;
087        
088        //TODO: is this still needed? I think it's obsolete now
089        private List boNotes;
090        
091        protected FormFile attachmentFile = new BlankFormFile();
092    
093        protected Map editingMode;
094        protected Map documentActions;
095        protected boolean suppressAllButtons;
096        
097        protected Map adHocActionRequestCodes;
098        private boolean returnToActionList;
099    
100        // for session enhancement
101        private String formKey;
102        private String docNum;
103        
104        private List<ActionRequest> actionRequests;
105        private List<String> selectedActionRequests;
106        private String superUserAnnotation;
107        
108        
109        /**
110         * Stores the error map from previous requests, so that we can continue to display error messages displayed during a previous request
111         */
112        private MessageMap errorMapFromPreviousRequest;
113        
114            /***
115         * @see KualiForm#addRequiredNonEditableProperties()
116         */
117        @Override
118        public void addRequiredNonEditableProperties(){
119            super.addRequiredNonEditableProperties();
120            registerRequiredNonEditableProperty(KRADConstants.DOCUMENT_TYPE_NAME);
121            registerRequiredNonEditableProperty(KRADConstants.FORM_KEY);
122            registerRequiredNonEditableProperty(KRADConstants.NEW_NOTE_NOTE_TYPE_CODE);
123        }
124    
125            /**
126             * @return the docNum
127             */
128            public String getDocNum() {
129                    return this.docNum;
130            }
131    
132            /**
133             * @param docNum
134             *            the docNum to set
135             */
136            public void setDocNum(String docNum) {
137                    this.docNum = docNum;
138            }
139        
140        /**
141         * no args constructor that just initializes things for us
142         */
143        @SuppressWarnings("unchecked")
144            public KualiDocumentFormBase() {
145            super();
146            
147            instantiateDocument();
148            newNote = new Note();
149            this.editingMode = new HashMap();
150            //this.additionalScriptFiles = new AutoPopulatingList(String.class);
151            this.additionalScriptFiles = new AutoPopulatingList<String>(String.class);
152    
153            // set the initial record for persons up
154            newAdHocRoutePerson = new AdHocRoutePerson();
155    
156            // set the initial record for workgroups up
157            newAdHocRouteWorkgroup = new AdHocRouteWorkgroup();
158    
159            // to make sure it posts back the correct time
160            setFormatterType("document.documentHeader.note.finDocNotePostedDttmStamp", TimestampAMPMFormatter.class);
161            setFormatterType("document.documentHeader.note.attachment.finDocNotePostedDttmStamp", TimestampAMPMFormatter.class);
162            //TODO: Chris - Notes: remove the above and change the below from boNotes when notes are finished
163            //overriding note formatter to make sure they post back the full timestamp
164            setFormatterType("document.documentHeader.boNote.notePostedTimestamp",TimestampAMPMFormatter.class);
165            setFormatterType("document.documentBusinessObject.boNote.notePostedTimestamp",TimestampAMPMFormatter.class);
166    
167            setFormatterType("editingMode", NoOpStringFormatter.class);
168            setFormatterType("editableAccounts", NoOpStringFormatter.class);
169    
170            setDocumentActions(new HashMap());
171            suppressAllButtons = false;
172            
173            initializeHeaderNavigationTabs();
174        }
175    
176        /**
177         * Setup workflow doc in the document.
178         */
179        @Override
180        public void populate(HttpServletRequest request) {
181            super.populate(request);
182    
183            WorkflowDocument workflowDocument = null;
184    
185            if (hasDocumentId()) {
186                // populate workflowDocument in documentHeader, if needed
187                    // KULRICE-4444 Obtain Document Header using the Workflow Service to minimize overhead
188                try {
189                    SessionDocumentService sessionDocumentService = KRADServiceLocatorWeb.getSessionDocumentService();
190                    workflowDocument = sessionDocumentService.getDocumentFromSession( GlobalVariables.getUserSession(), getDocument().getDocumentNumber());
191                            if ( workflowDocument == null)
192                            {
193                        // gets the workflow document from doc service, doc service will also set the workflow document in the
194                        // user's session
195                                    Person person = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(KRADConstants.SYSTEM_USER);
196                                    workflowDocument = KRADServiceLocatorWeb.getWorkflowDocumentService().loadWorkflowDocument(getDocument().getDocumentNumber(), person);
197                                    sessionDocumentService.addDocumentToUserSession(GlobalVariables.getUserSession(), workflowDocument);
198                                    if (workflowDocument == null)
199                                    {
200                                            throw new WorkflowException("Unable to retrieve workflow document # " + getDocument().getDocumentNumber() + " from workflow document service createWorkflowDocument");
201                                    }
202                                    else
203                                    {
204                                    LOG.debug("Retrieved workflow Document ID: " + workflowDocument.getDocumentId());
205                                    }
206                            }
207    
208                    getDocument().getDocumentHeader().setWorkflowDocument(workflowDocument);
209                } catch (WorkflowException e) {
210                    LOG.warn("Error while instantiating workflowDoc", e);
211                    throw new RuntimeException("error populating documentHeader.workflowDocument", e);
212                }
213            } 
214            if (workflowDocument != null) {
215                    //Populate Document Header attributes
216                    populateHeaderFields(workflowDocument);
217            }
218        }
219        
220        protected String getPersonInquiryUrlLink(Person user, String linkBody) {
221            StringBuffer urlBuffer = new StringBuffer();
222            
223            if(user != null && StringUtils.isNotEmpty(linkBody) ) {
224                    ModuleService moduleService = KRADServiceLocatorWeb.getKualiModuleService().getResponsibleModuleService(Person.class);
225                    Map<String, String[]> parameters = new HashMap<String, String[]>();
226                    parameters.put(KimConstants.AttributeConstants.PRINCIPAL_ID, new String[] { user.getPrincipalId() });
227                    String inquiryUrl = moduleService.getExternalizableBusinessObjectInquiryUrl(Person.class, parameters);
228                if(!StringUtils.equals(KimConstants.EntityTypes.SYSTEM, user.getEntityTypeCode())){
229                        urlBuffer.append("<a href='");
230                        urlBuffer.append(inquiryUrl);
231                        urlBuffer.append("' ");
232                        urlBuffer.append("target='_blank'");
233                        urlBuffer.append("title='Person Inquiry'>");
234                        urlBuffer.append(linkBody);
235                        urlBuffer.append("</a>");
236                } else{
237                    urlBuffer.append(linkBody);
238                }
239            }
240            
241            return urlBuffer.toString();
242        }
243        
244        protected String getDocumentHandlerUrl(String documentId) {
245            Properties parameters = new Properties();
246            parameters.put(KRADConstants.PARAMETER_DOC_ID, documentId);
247            parameters.put(KRADConstants.PARAMETER_COMMAND, KRADConstants.METHOD_DISPLAY_DOC_SEARCH_VIEW);
248            return UrlFactory.parameterizeUrl(
249                    KRADServiceLocator.getKualiConfigurationService().getPropertyValueAsString(
250                            KRADConstants.WORKFLOW_URL_KEY) + "/" + KRADConstants.DOC_HANDLER_ACTION, parameters);
251        }
252        
253        protected String buildHtmlLink(String url, String linkBody) {
254            StringBuffer urlBuffer = new StringBuffer();
255            
256            if(StringUtils.isNotEmpty(url) && StringUtils.isNotEmpty(linkBody) ) {
257                urlBuffer.append("<a href='").append(url).append("'>").append(linkBody).append("</a>");
258            }
259            
260            return urlBuffer.toString();
261        }
262        
263        /**
264             * This method is used to populate the list of header field objects (see {@link KualiForm#getDocInfo()}) displayed on
265             * the Kuali document form display pages.
266             * 
267             * @param workflowDocument - the workflow document of the document being displayed (null is allowed)
268             */
269            public void populateHeaderFields(WorkflowDocument workflowDocument) {
270                    getDocInfo().clear();
271                    getDocInfo().addAll(getStandardHeaderFields(workflowDocument));
272            }
273    
274            /**
275             * This method returns a list of {@link HeaderField} objects that are used by default on Kuali document display pages. To
276             * use this list and override an individual {@link HeaderField} object the id constants from
277             * {@link org.kuali.rice.krad.util.KRADConstants.DocumentFormHeaderFieldIds} can be used to identify items from the list.
278             * 
279             * @param workflowDocument - the workflow document of the document being displayed (null is allowed)
280             * @return a list of the standard fields displayed by default for all Kuali documents
281             */
282        protected List<HeaderField> getStandardHeaderFields(WorkflowDocument workflowDocument) {
283            List<HeaderField> headerFields = new ArrayList<HeaderField>();
284            setNumColumns(2);
285            // check for a document template number as that will dictate column numbering
286            HeaderField docTemplateNumber = null;
287            if ((ObjectUtils.isNotNull(getDocument())) && (ObjectUtils.isNotNull(getDocument().getDocumentHeader())) && (StringUtils.isNotBlank(getDocument().getDocumentHeader().getDocumentTemplateNumber()))) {
288                            String templateDocumentNumber = getDocument().getDocumentHeader().getDocumentTemplateNumber();
289                            docTemplateNumber = new HeaderField(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_TEMPLATE_NUMBER, "DataDictionary.DocumentHeader.attributes.documentTemplateNumber",
290                                            templateDocumentNumber, buildHtmlLink(getDocumentHandlerUrl(templateDocumentNumber), templateDocumentNumber));
291                    }
292            //Document Number       
293            HeaderField docNumber = new HeaderField("DataDictionary.DocumentHeader.attributes.documentNumber", workflowDocument != null? getDocument().getDocumentNumber() : null);
294            docNumber.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_NUMBER);
295            HeaderField docStatus = new HeaderField("DataDictionary.AttributeReferenceDummy.attributes.workflowDocumentStatus", workflowDocument != null? workflowDocument.getStatus().getLabel() : null);
296            docStatus.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_WORKFLOW_STATUS);
297            String initiatorNetworkId = null;
298            Person user = null;
299            if (workflowDocument != null) {
300                    if (getInitiator() == null) {
301                            LOG.warn("User Not Found while attempting to build inquiry link for document header fields");
302                    } else {
303                            user = getInitiator();
304                            initiatorNetworkId = getInitiator().getPrincipalName();
305                    }
306            }
307            String inquiryUrl = getPersonInquiryUrlLink(user, workflowDocument != null? initiatorNetworkId:null);
308    
309            HeaderField docInitiator = new HeaderField(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_INITIATOR, "DataDictionary.AttributeReferenceDummy.attributes.initiatorNetworkId",
310            workflowDocument != null? initiatorNetworkId : null, workflowDocument != null? inquiryUrl : null);
311            
312            String createDateStr = null;
313            if(workflowDocument != null && workflowDocument.getDateCreated() != null) {
314                createDateStr = CoreApiServiceLocator.getDateTimeService().toString(workflowDocument.getDateCreated().toDate(), "hh:mm a MM/dd/yyyy");
315            }
316            
317            HeaderField docCreateDate = new HeaderField("DataDictionary.AttributeReferenceDummy.attributes.createDate", createDateStr);
318            docCreateDate.setId(KRADConstants.DocumentFormHeaderFieldIds.DOCUMENT_CREATE_DATE);
319            if (ObjectUtils.isNotNull(docTemplateNumber)) {
320                    setNumColumns(3);
321            }
322            
323            headerFields.add(docNumber);
324            headerFields.add(docStatus);
325            if (ObjectUtils.isNotNull(docTemplateNumber)) {
326                    headerFields.add(docTemplateNumber);
327            }
328            headerFields.add(docInitiator);
329            headerFields.add(docCreateDate);
330            if (ObjectUtils.isNotNull(docTemplateNumber)) {
331                    // adding an empty field so implementors do not have to worry about additional fields being put on the wrong row
332                    headerFields.add(HeaderField.EMPTY_FIELD);
333            }
334            return headerFields;
335        }    
336    
337        /**
338         * @see org.apache.struts.action.ActionForm#validate(org.apache.struts.action.ActionMapping,
339         *      javax.servlet.http.HttpServletRequest)
340         */
341        @Override
342        public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
343            // check that annotation does not exceed 2000 characters
344            setAnnotation(StringUtils.stripToNull(getAnnotation()));
345            int diff = StringUtils.defaultString(getAnnotation()).length() - KRADConstants.DOCUMENT_ANNOTATION_MAX_LENGTH;
346            if (diff > 0) {
347                GlobalVariables.getMessageMap().putError("annotation", RiceKeyConstants.ERROR_DOCUMENT_ANNOTATION_MAX_LENGTH_EXCEEDED, new String[] { Integer.toString(KRADConstants.DOCUMENT_ANNOTATION_MAX_LENGTH), Integer.toString(diff) });
348            }
349            return super.validate(mapping, request);
350        }
351    
352        /**
353         * @return true if this document was properly initialized with a DocumentHeader and related KualiWorkflowDocument
354         */
355        final public boolean isFormDocumentInitialized() {
356            boolean initialized = false;
357    
358            if (document != null) {
359                if (document.getDocumentHeader() != null) {
360                    initialized = document.getDocumentHeader().hasWorkflowDocument();
361                }
362            }
363    
364            return initialized;
365        }
366    
367    
368        /**
369         * @return Map of editingModes for this document, as set during the most recent call to
370         *         populate(javax.servlet.http.HttpServletRequest)
371         */
372        @SuppressWarnings("unchecked")
373            public Map getEditingMode() {
374            return editingMode;
375        }
376    
377        /**
378         * Set editingMode for this document
379         */
380        @SuppressWarnings("unchecked")
381            public void setEditingMode(Map editingMode) {
382            this.editingMode = editingMode;
383        }
384        
385        /**
386             * @return the documentActions
387             */
388            @SuppressWarnings("unchecked")
389            public Map getDocumentActions() {
390                    return this.documentActions;
391            }
392    
393            /**
394             * @param documentActions the documentActions to set
395             */
396            @SuppressWarnings("unchecked")
397            public void setDocumentActions(Map documentActions) {
398                    this.documentActions = documentActions;
399            }
400            
401            
402    
403            /**
404             * @param adHocActionRequestCodes the adHocActionRequestCodes to set
405             */
406            @SuppressWarnings("unchecked")
407            public void setAdHocActionRequestCodes(Map adHocActionRequestCodes) {
408                    this.adHocActionRequestCodes = adHocActionRequestCodes;
409            }
410    
411            /**
412         * @return a map of the possible action request codes that takes into account the users context on the document
413         */
414        @SuppressWarnings("unchecked")
415            public Map getAdHocActionRequestCodes() {
416            //Map adHocActionRequestCodes = new HashMap();
417            //KRADServiceLocatorInternal.getDocumentHelperService()
418            /*if (getWorkflowDocument() != null) {
419                if (getWorkflowDocument().isFYIRequested()) {
420                    adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL);
421                }
422                else if (getWorkflowDocument().isAcknowledgeRequested()) {
423                    adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ, KewApiConstants.ACTION_REQUEST_ACKNOWLEDGE_REQ_LABEL);
424                    adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_FYI_REQ, KewApiConstants.ACTION_REQUEST_FYI_REQ_LABEL);
425                }
426                else if (getWorkflowDocument().isApprovalRequested() || getWorkflowDocument().isCompletionRequested() || getWorkflowDocument().stateIsInitiated() || getWorkflowDocument().stateIsSaved()) {
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                    adHocActionRequestCodes.put(KewApiConstants.ACTION_REQUEST_APPROVE_REQ, KewApiConstants.ACTION_REQUEST_APPROVE_REQ_LABEL);
430                }
431            }*/
432            return adHocActionRequestCodes;
433        }
434    
435    
436        /**
437         * @return the list of ad hoc routing persons
438         */
439        public List<AdHocRoutePerson> getAdHocRoutePersons() {
440            return document.getAdHocRoutePersons();
441        }
442    
443    
444        /**
445         * @return attachmentFile
446         */
447        public FormFile getAttachmentFile() {
448            return attachmentFile;
449        }
450    
451        /**
452         * @param attachmentFile The attachmentFile to set.
453         */
454        public void setAttachmentFile(FormFile attachmentFile) {
455            this.attachmentFile = attachmentFile;
456        }
457    
458    
459        /**
460         * set the ad hoc routing persons list
461         *
462         * @param adHocRouteRecipients
463         */
464        public void setAdHocRoutePersons(List<AdHocRoutePerson> adHocRouteRecipients) {
465            document.setAdHocRoutePersons(adHocRouteRecipients);
466        }
467    
468        /**
469         * get the ad hoc routing workgroup requests
470         *
471         * @return
472         */
473        public List<AdHocRouteWorkgroup> getAdHocRouteWorkgroups() {
474            return document.getAdHocRouteWorkgroups();
475        }
476    
477        /**
478         * set the ad hoc routing workgroup requests
479         *
480         * @param adHocRouteWorkgroups
481         */
482        public void setAdHocRouteWorkgroups(List<AdHocRouteWorkgroup> adHocRouteWorkgroups) {
483            document.setAdHocRouteWorkgroups(adHocRouteWorkgroups);
484        }
485    
486        /**
487         * Special getter based on index to work with multi rows for ad hoc routing to persons struts page
488         *
489         * @param index
490         * @return
491         */
492        public AdHocRoutePerson getAdHocRoutePerson(int index) {
493            while (getAdHocRoutePersons().size() <= index) {
494                getAdHocRoutePersons().add(new AdHocRoutePerson());
495            }
496            return getAdHocRoutePersons().get(index);
497        }
498    
499        /**
500         * Special getter based on index to work with multi rows for ad hoc routing to workgroups struts page
501         *
502         * @param index
503         * @return
504         */
505        public AdHocRouteWorkgroup getAdHocRouteWorkgroup(int index) {
506            while (getAdHocRouteWorkgroups().size() <= index) {
507                getAdHocRouteWorkgroups().add(new AdHocRouteWorkgroup());
508            }
509            return getAdHocRouteWorkgroups().get(index);
510        }
511    
512        /**
513         * @return the new ad hoc route person object
514         */
515        public AdHocRoutePerson getNewAdHocRoutePerson() {
516            return newAdHocRoutePerson;
517        }
518    
519        /**
520         * set the new ad hoc route person object
521         *
522         * @param newAdHocRoutePerson
523         */
524        public void setNewAdHocRoutePerson(AdHocRoutePerson newAdHocRoutePerson) {
525            this.newAdHocRoutePerson = newAdHocRoutePerson;
526        }
527    
528        /**
529         * @return the new ad hoc route workgroup object
530         */
531        public AdHocRouteWorkgroup getNewAdHocRouteWorkgroup() {
532            return newAdHocRouteWorkgroup;
533        }
534    
535        /**
536         * set the new ad hoc route workgroup object
537         *
538         * @param newAdHocRouteWorkgroup
539         */
540        public void setNewAdHocRouteWorkgroup(AdHocRouteWorkgroup newAdHocRouteWorkgroup) {
541            this.newAdHocRouteWorkgroup = newAdHocRouteWorkgroup;
542        }
543    
544        /**
545         * @return Returns the Document
546         */
547        public Document getDocument() {
548            return document;
549        }
550    
551        /**
552         * @param document
553         */
554        public void setDocument(Document document) {
555            this.document = document;
556            if(document != null && StringUtils.isNotEmpty(document.getDocumentNumber())) {
557                populateHeaderFields(document.getDocumentHeader().getWorkflowDocument());
558            }
559        }
560    
561        /**
562         * @return WorkflowDocument for this form's document
563         */
564        public WorkflowDocument getWorkflowDocument() {
565            return getDocument().getDocumentHeader().getWorkflowDocument();
566        }
567        
568        /**
569             *  Null-safe check to see if the workflow document object exists before attempting to retrieve it.
570         *  (Which, if called, will throw an exception.)
571             */
572        public boolean isHasWorkflowDocument() {
573            if ( getDocument() == null || getDocument().getDocumentHeader() == null ) {
574                    return false;
575            }
576            return getDocument().getDocumentHeader().hasWorkflowDocument();
577        }
578    
579        /**
580         * TODO rk implemented to account for caps coming from kuali user service from workflow
581         */
582        public boolean isUserDocumentInitiator() {
583            if (getWorkflowDocument() != null) {
584                return getWorkflowDocument().getInitiatorPrincipalId().equalsIgnoreCase(
585                            GlobalVariables.getUserSession().getPrincipalId());
586            }
587            return false;
588        }
589    
590        public Person getInitiator() {
591            String initiatorPrincipalId = getWorkflowDocument().getInitiatorPrincipalId();
592            return KimApiServiceLocator.getPersonService().getPerson(initiatorPrincipalId);
593        }
594    
595        /**
596         * @return true if the workflowDocument associated with this form is currently enroute
597         */
598        public boolean isDocumentEnRoute() {
599            return getWorkflowDocument().isEnroute();
600        }
601    
602        /**
603         * @param annotation The annotation to set.
604         */
605        public void setAnnotation(String annotation) {
606            this.annotation = annotation;
607        }
608    
609        /**
610         * @return Returns the annotation.
611         */
612        public String getAnnotation() {
613            return annotation;
614        }
615    
616        /**
617         * @return returns the command that was passed from workflow
618         */
619        public String getCommand() {
620            return command;
621        }
622    
623        /**
624         * setter for the command that was passed from workflow on the url
625         *
626         * @param command
627         */
628        public void setCommand(String command) {
629            this.command = command;
630        }
631    
632        /**
633         * @return returns the docId that was passed from workflow on the url
634         */
635        public String getDocId() {
636            return docId;
637        }
638    
639        /**
640         * setter for the docId that was passed from workflow on the url
641         *
642         * @param docId
643         */
644        public void setDocId(String docId) {
645            this.docId = docId;
646        }
647    
648        /**
649         * getter for the docTypeName that was passed from workflow on the url
650         *
651         * @return
652         */
653        public String getDocTypeName() {
654            return docTypeName;
655        }
656    
657        /**
658         * setter for the docTypeName that was passed from workflow on the url
659         *
660         * @param docTypeName
661         */
662        public void setDocTypeName(String docTypeName) {
663            this.docTypeName = docTypeName;
664        }
665    
666        /**
667         * getter for convenience that will return the initiators network id
668         *
669         * @return
670         */
671        public String getInitiatorNetworkId() {
672            return this.getWorkflowDocument().getInitiatorPrincipalId();
673        }
674    
675        /**
676         * Gets the suppressAllButtons attribute.
677         *
678         * @return Returns the suppressAllButtons.
679         */
680        public final boolean isSuppressAllButtons() {
681            return suppressAllButtons;
682        }
683    
684        /**
685         * Sets the suppressAllButtons attribute value.
686         *
687         * @param suppressAllButtons The suppressAllButtons to set.
688         */
689        public final void setSuppressAllButtons(boolean suppressAllButtons) {
690            this.suppressAllButtons = suppressAllButtons;
691        }
692    
693        /**
694         * @return true if this form's getDocument() method returns a Document, and if that Document's getDocumentHeaderId method
695         *         returns a non-null
696         */
697        public boolean hasDocumentId() {
698            boolean hasDocId = false;
699    
700            Document d = getDocument();
701            if (d != null) {
702                String docHeaderId = d.getDocumentNumber();
703    
704                hasDocId = StringUtils.isNotBlank(docHeaderId);
705            }
706    
707            return hasDocId;
708        }
709    
710        /**
711         * Sets flag indicating whether upon completion of approve, blanketApprove, cancel, or disapprove, the user should be returned
712         * to the actionList instead of to the portal
713         *
714         * @param returnToActionList
715         */
716        public void setReturnToActionList(boolean returnToActionList) {
717            this.returnToActionList = returnToActionList;
718        }
719    
720        public boolean isReturnToActionList() {
721            return returnToActionList;
722        }
723    
724        public List<String> getAdditionalScriptFiles() {
725            return additionalScriptFiles;
726        }
727    
728        public void setAdditionalScriptFiles(List<String> additionalScriptFiles) {
729            this.additionalScriptFiles = additionalScriptFiles;
730        }
731    
732        public void setAdditionalScriptFile( int index, String scriptFile ) {
733            additionalScriptFiles.set( index, scriptFile );
734            }
735    
736        public String getAdditionalScriptFile( int index ) {
737            return additionalScriptFiles.get( index );
738        }
739    
740        public Note getNewNote() {
741            return newNote;
742        }
743    
744        public void setNewNote(Note newNote) {
745            this.newNote = newNote;
746        }
747    
748        /**
749         * Gets the boNotes attribute. 
750         * @return Returns the boNotes.
751         */
752        @SuppressWarnings("unchecked")
753            public List getBoNotes() {
754            return boNotes;
755        }
756    
757        /**
758         * Sets the boNotes attribute value.
759         * @param boNotes The boNotes to set.
760         */
761        @SuppressWarnings("unchecked")
762            public void setBoNotes(List boNotes) {
763            this.boNotes = boNotes;
764        }
765    
766        public String getFormKey() {
767            return this.formKey;
768        }
769    
770        public void setFormKey(String formKey) {
771            this.formKey = formKey;
772        }
773    
774        /* Reset method
775         * This is initially created for session document implementation
776         * @param mapping
777         * @param request
778         */
779        @Override
780        public void reset(ActionMapping mapping, HttpServletRequest request) {
781            super.reset(mapping, request);
782            this.setMethodToCall(null);
783            this.setRefreshCaller(null);
784            this.setAnchor(null);
785            this.setCurrentTabIndex(0);
786            this.setSelectedActionRequests(new ArrayList<String>());
787        }
788    
789        
790        /**
791         * Adds the attachment file size to the list of max file sizes.
792         * 
793         * @see org.kuali.rice.krad.web.struts.pojo.PojoFormBase#customInitMaxUploadSizes()
794         */
795        @Override
796        protected void customInitMaxUploadSizes() {
797            super.customInitMaxUploadSizes();
798            addMaxUploadSize(CoreFrameworkServiceLocator.getParameterService().getParameterValueAsString(KRADConstants.KNS_NAMESPACE, KRADConstants.DetailTypes.DOCUMENT_DETAIL_TYPE, KRADConstants.ATTACHMENT_MAX_FILE_SIZE_PARM_NM));
799        }
800    
801        
802        
803            /**
804             * This overridden method ...
805             * IMPORTANT: any overrides of this method must ensure that nothing in the HTTP request will be used to determine whether document is in session 
806             * 
807             * @see org.kuali.rice.krad.web.struts.pojo.PojoFormBase#shouldPropertyBePopulatedInForm(java.lang.String, javax.servlet.http.HttpServletRequest)
808             */
809            @Override
810            public boolean shouldPropertyBePopulatedInForm(String requestParameterName, HttpServletRequest request) {
811                    for ( String prefix : KRADConstants.ALWAYS_VALID_PARAMETER_PREFIXES ) {
812                            if (requestParameterName.startsWith(prefix)) {
813                                    return true;
814                            }
815                    }
816    
817                    if (StringUtils.equalsIgnoreCase(getMethodToCall(), KRADConstants.DOC_HANDLER_METHOD)) {
818                            return true;
819                    }
820                    if (WebUtils.isDocumentSession(getDocument(), this)) {
821                            return isPropertyEditable(requestParameterName) || isPropertyNonEditableButRequired(requestParameterName);
822                    }
823                    return true;
824            }
825    
826            /**
827             * This overridden method ...
828             * 
829             * @see KualiForm#shouldMethodToCallParameterBeUsed(java.lang.String, java.lang.String, javax.servlet.http.HttpServletRequest)
830             */
831            @Override
832            public boolean shouldMethodToCallParameterBeUsed(
833                            String methodToCallParameterName,
834                            String methodToCallParameterValue, HttpServletRequest request) {
835                    if (StringUtils.equals(methodToCallParameterName, KRADConstants.DISPATCH_REQUEST_PARAMETER) &&
836                                    StringUtils.equals(methodToCallParameterValue, KRADConstants.DOC_HANDLER_METHOD)) {
837                            return true;
838                    }
839                    return super.shouldMethodToCallParameterBeUsed(methodToCallParameterName,
840                                    methodToCallParameterValue, request);
841            }
842            
843            public MessageMap getMessageMapFromPreviousRequest() {
844                    return this.errorMapFromPreviousRequest;
845            }
846            
847            public void setMessageMapFromPreviousRequest(MessageMap errorMapFromPreviousRequest) {
848                    this.errorMapFromPreviousRequest = errorMapFromPreviousRequest;
849            }
850            
851            @Override
852            public void setDerivedValuesOnForm(HttpServletRequest request) {
853                    super.setDerivedValuesOnForm(request);
854    
855                    String docTypeName = getDocTypeName();
856                    if (StringUtils.isNotBlank(docTypeName)) {
857                            DataDictionary dataDictionary = KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary();
858    
859                Class<? extends DerivedValuesSetter> derivedValuesSetterClass = null;
860                KNSDocumentEntry documentEntry = (KNSDocumentEntry) dataDictionary.getDocumentEntry(docTypeName);
861                derivedValuesSetterClass = (documentEntry).getDerivedValuesSetterClass();
862    
863                            if (derivedValuesSetterClass != null) {
864                                    DerivedValuesSetter derivedValuesSetter = null;
865                                    try {
866                                            derivedValuesSetter = derivedValuesSetterClass.newInstance();
867                                    }
868    
869                                    catch (Exception e) {
870                                            LOG.error("Unable to instantiate class " + derivedValuesSetterClass.getName(), e);
871                                            throw new RuntimeException("Unable to instantiate class " + derivedValuesSetterClass.getName(), e);
872                                    }
873                                    derivedValuesSetter.setDerivedValues(this, request);
874                            }
875                    }
876            }
877            
878            protected String getDefaultDocumentTypeName() {
879                    return "";
880            }
881            
882            /** will instatiate a new document setting it on the form if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value. */
883            protected void instantiateDocument() {
884                    if (document == null && StringUtils.isNotBlank(getDefaultDocumentTypeName())) {
885                            Class<? extends Document> documentClass = getDocumentClass();
886                            try {
887                                    Document document = documentClass.newInstance();
888                                    setDocument(document);
889                            } catch (Exception e) {
890                                    LOG.error("Unable to instantiate document class " + documentClass.getName() + " document type " + getDefaultDocumentTypeName());
891                                    throw new RuntimeException(e);
892                            }
893                    }
894            }
895            
896            /** gets the document class from the datadictionary if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value otherwise behavior is nondeterministic. */
897            private Class<? extends Document> getDocumentClass() {
898                    return KRADServiceLocatorWeb.getDataDictionaryService().getDocumentClassByTypeName(getDefaultDocumentTypeName());
899            }
900            
901            /**initializes the header tabs from what is defined in the datadictionary if {@link KualiDocumentFormBase#getDefaultDocumentTypeName()} is overriden to return a valid value. */
902        protected void initializeHeaderNavigationTabs() {
903            if (StringUtils.isNotBlank(getDefaultDocumentTypeName())) {
904                    final KNSDocumentEntry docEntry = (KNSDocumentEntry) KRADServiceLocatorWeb.getDataDictionaryService().getDataDictionary().getDocumentEntry(getDocumentClass().getName());
905                    final List<HeaderNavigation> navList = docEntry.getHeaderNavigationList();
906                    final HeaderNavigation[] list = new HeaderNavigation[navList.size()];
907                    super.setHeaderNavigationTabs(navList.toArray(list));
908            }
909        }
910        
911        public List<ActionRequest> getActionRequests() {
912                    return actionRequests;
913            }
914    
915            public void setActionRequests(List<ActionRequest> actionRequests) {
916                    this.actionRequests = actionRequests;
917            }
918    
919            public List<String> getSelectedActionRequests() {
920                    return selectedActionRequests;
921            }
922    
923            public void setSelectedActionRequests(List<String> selectedActionRequests) {
924                    this.selectedActionRequests = selectedActionRequests;
925            }
926    
927            public String getSuperUserAnnotation() {
928                    return superUserAnnotation;
929            }
930    
931            public void setSuperUserAnnotation(String superUserAnnotation) {
932                    this.superUserAnnotation = superUserAnnotation;
933            }
934            
935            public boolean isSuperUserAuthorized() {
936                    return KewApiServiceLocator.getDocumentTypeService().isSuperUserForDocumentTypeName(GlobalVariables.getUserSession().getPrincipalId(), this.getDocTypeName());
937            }
938            
939            public boolean isStateAllowsSuperUserAction() {
940             if(this.getDocument().getDocumentHeader().hasWorkflowDocument()) {
941                DocumentStatus status = this.getDocument().getDocumentHeader().getWorkflowDocument().getStatus();
942                return !(StringUtils.equals(status.getCode(), DocumentStatus.PROCESSED.getCode()) ||
943                         StringUtils.equals(status.getCode(), DocumentStatus.DISAPPROVED.getCode()) ||
944                         StringUtils.equals(status.getCode(), DocumentStatus.FINAL.getCode()));
945             } else {
946                 return false;
947             }
948            }
949            
950            public boolean isSuperUserDocument() {
951            if(this.getDocument().getDocumentHeader().hasWorkflowDocument()) {
952                DocumentStatus status = this.getDocument().getDocumentHeader().getWorkflowDocument().getStatus();
953                return !(StringUtils.equals(status.getCode(), DocumentStatus.INITIATED.getCode()) || StringUtils.equals(status.getCode(), DocumentStatus.SAVED.getCode()));
954            } else {
955                return false;
956            }
957            }
958    }