Coverage Report - org.kuali.rice.edl.impl.components.WorkflowDocumentState
 
Classes in this File Line Coverage Branch Coverage Complexity
WorkflowDocumentState
0%
0/117
0%
0/58
7
WorkflowDocumentState$buttons
0%
0/2
N/A
7
 
 1  
 /*
 2  
  * Copyright 2006-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 
 17  
 package org.kuali.rice.edl.impl.components;
 18  
 
 19  
 import java.util.ArrayList;
 20  
 import java.util.Date;
 21  
 import java.util.Iterator;
 22  
 import java.util.List;
 23  
 import java.util.Map;
 24  
 
 25  
 import javax.xml.xpath.XPath;
 26  
 import javax.xml.xpath.XPathConstants;
 27  
 import javax.xml.xpath.XPathExpressionException;
 28  
 import javax.xml.xpath.XPathFactory;
 29  
 
 30  
 import org.apache.commons.lang.StringUtils;
 31  
 import org.apache.log4j.Logger;
 32  
 import org.kuali.rice.core.framework.services.CoreFrameworkServiceLocator;
 33  
 import org.kuali.rice.core.util.RiceConstants;
 34  
 import org.kuali.rice.core.util.xml.XmlJotter;
 35  
 import org.kuali.rice.edl.impl.EDLContext;
 36  
 import org.kuali.rice.edl.impl.EDLModelComponent;
 37  
 import org.kuali.rice.edl.impl.EDLXmlUtils;
 38  
 import org.kuali.rice.edl.impl.RequestParser;
 39  
 import org.kuali.rice.edl.impl.UserAction;
 40  
 import org.kuali.rice.edl.impl.service.EdlServiceLocator;
 41  
 import org.kuali.rice.kew.api.WorkflowDocument;
 42  
 import org.kuali.rice.kew.api.WorkflowRuntimeException;
 43  
 import org.kuali.rice.kew.exception.WorkflowException;
 44  
 import org.kuali.rice.kew.service.WorkflowInfo;
 45  
 import org.kuali.rice.kew.util.KEWConstants;
 46  
 import org.kuali.rice.krad.util.KRADConstants;
 47  
 import org.w3c.dom.Document;
 48  
 import org.w3c.dom.Element;
 49  
 
 50  
 
 51  
 /**
 52  
  * Generates document state based on the workflow document in session.
 53  
  *
 54  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 55  
  *
 56  
  */
 57  0
 public class WorkflowDocumentState implements EDLModelComponent {
 58  
 
 59  0
         private static final Logger LOG = Logger.getLogger(WorkflowDocumentState.class);
 60  
 
 61  
         // The order the enum values are listed determines the order the buttons appear on the screen
 62  0
         private enum buttons{ACKNOWLEDGE, BLANKETAPPROVE, ROUTE, SAVE, COMPLETE, APPROVE, DISAPPROVE, 
 63  0
             RETURNTOPREVIOUS, FYI, CANCEL};
 64  
         
 65  
         public void updateDOM(Document dom, Element configElement, EDLContext edlContext) {
 66  
 
 67  
                 try {
 68  0
                         Element documentState = EDLXmlUtils.getDocumentStateElement(dom);
 69  
 
 70  0
                         Element dateTime = EDLXmlUtils.getOrCreateChildElement(documentState, "dateTime", true);
 71  0
                         dateTime.appendChild(dom.createTextNode(RiceConstants.getDefaultDateAndTimeFormat().format(new Date())));
 72  
 
 73  0
                         Element definition = EDLXmlUtils.getOrCreateChildElement(documentState, "definition", true);
 74  0
                         definition.appendChild(dom.createTextNode(edlContext.getEdocLiteAssociation().getDefinition()));
 75  
 
 76  0
                         Element docType = EDLXmlUtils.getOrCreateChildElement(documentState, "docType", true);
 77  0
                         docType.appendChild(dom.createTextNode(edlContext.getEdocLiteAssociation().getEdlName()));
 78  
 
 79  0
                         Element style = EDLXmlUtils.getOrCreateChildElement(documentState, "style", true);
 80  0
                         String styleName = edlContext.getEdocLiteAssociation().getStyle();
 81  0
                         if (styleName == null) {
 82  0
                                 styleName = "Default";
 83  
                         }
 84  0
                         style.appendChild(dom.createTextNode(styleName));
 85  
 
 86  0
                         Element showAttachments = EDLXmlUtils.getOrCreateChildElement(documentState, "showAttachments", true);
 87  0
                         boolean showConstants = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean(KEWConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.ALL_DETAIL_TYPE, KEWConstants.SHOW_ATTACHMENTS_IND);
 88  
 
 89  0
                         showAttachments.appendChild(dom.createTextNode(Boolean.valueOf(showConstants).toString()));
 90  
 
 91  0
                         WorkflowDocument document = (WorkflowDocument)edlContext.getRequestParser().getAttribute(RequestParser.WORKFLOW_DOCUMENT_SESSION_KEY);
 92  0
                         WorkflowInfo info = new WorkflowInfo();
 93  
 
 94  0
                         boolean documentEditable = false;
 95  0
                         if (document != null) {
 96  0
                                 List<String> validActions = determineValidActions(document);
 97  
                                 
 98  0
                                 documentEditable = isEditable(edlContext, validActions);
 99  
         
 100  0
                                 edlContext.getTransformer().setParameter("readOnly", String.valueOf(documentEditable));
 101  0
                                 addActions(dom, documentState, validActions);
 102  0
                                 boolean isAnnotatable = isAnnotatable(validActions);
 103  0
                                 EDLXmlUtils.createTextElementOnParent(documentState, "annotatable", String.valueOf(isAnnotatable));
 104  0
                                 EDLXmlUtils.createTextElementOnParent(documentState, "docId", document.getDocumentId());
 105  0
                                 Element workflowDocumentStatus = EDLXmlUtils.getOrCreateChildElement(documentState, "workflowDocumentState", true);
 106  0
                                 EDLXmlUtils.createTextElementOnParent(workflowDocumentStatus, "status", document.getStatus().getLabel());
 107  0
                                 EDLXmlUtils.createTextElementOnParent(workflowDocumentStatus, "createDate", RiceConstants.getDefaultDateAndTimeFormat().format(document.getDateCreated().toDate()));
 108  0
                                 List<String> nodeNames = document.getPreviousNodeNames();
 109  0
                                 if (nodeNames.size() > 0) {
 110  0
                                     Element previousNodes = EDLXmlUtils.getOrCreateChildElement(documentState, "previousNodes", true);
 111  
                                     // don't include LAST node (where the document is currently...don't want to return to current location)
 112  0
                                     for (int i = 0; i < nodeNames.size(); i++) {
 113  0
                                         EDLXmlUtils.createTextElementOnParent(previousNodes, "node", nodeNames.get(i));
 114  
                                     }
 115  
                                 }
 116  0
                                 String[] currentNodeNames = info.getCurrentNodeNames(document.getDocumentId());
 117  0
                                 for (String currentNodeName : currentNodeNames) {
 118  0
                                     EDLXmlUtils.createTextElementOnParent(documentState, "currentNodeName", currentNodeName);
 119  
                                 }
 120  
 
 121  
                         }
 122  
 
 123  0
                         Element editable = EDLXmlUtils.getOrCreateChildElement(documentState, "editable", true);
 124  0
                         editable.appendChild(dom.createTextNode(String.valueOf(documentEditable)));
 125  
 
 126  
                         // display the buttons
 127  0
                         EDLXmlUtils.createTextElementOnParent(documentState, "actionable", "true");
 128  
 
 129  0
                         List globalErrors = (List)edlContext.getRequestParser().getAttribute(RequestParser.GLOBAL_ERRORS_KEY);
 130  0
                         List globalMessages = (List)edlContext.getRequestParser().getAttribute(RequestParser.GLOBAL_MESSAGES_KEY);
 131  0
                         Map<String, String> globalFieldErrors = (Map)edlContext.getRequestParser().getAttribute(RequestParser.GLOBAL_FIELD_ERRORS_KEY);
 132  0
                         EDLXmlUtils.addErrorsAndMessagesToDocument(dom, globalErrors, globalMessages, globalFieldErrors);
 133  0
             if (LOG.isDebugEnabled()) {
 134  0
                     LOG.debug("Transforming dom " + XmlJotter.jotNode(dom, true));
 135  
             }
 136  0
                 } catch (Exception e) {
 137  0
                         throw new WorkflowRuntimeException(e);
 138  0
                 }
 139  0
         }
 140  
 
 141  
     public static List<String> determineValidActions(WorkflowDocument wfdoc) throws WorkflowException {
 142  0
         String[] flags = new String[10];
 143  0
         List<String> list = new ArrayList<String>();
 144  
         
 145  0
         if (wfdoc == null) {
 146  0
             list.add(UserAction.ACTION_CREATE);
 147  0
             return list;
 148  
         }
 149  
         
 150  0
         if (wfdoc.isAcknowledgeRequested()) {
 151  0
             flags[buttons.ACKNOWLEDGE.ordinal()] = UserAction.ACTION_ACKNOWLEDGE;
 152  
         }
 153  
         
 154  0
         if (wfdoc.isApprovalRequested()) {
 155  0
             if (wfdoc.isBlanketApproveCapable()) {
 156  0
                 flags[buttons.BLANKETAPPROVE.ordinal()] = UserAction.ACTION_BLANKETAPPROVE;
 157  
             }
 158  0
             if (!wfdoc.isSaved()) {
 159  0
                 flags[buttons.APPROVE.ordinal()] = UserAction.ACTION_APPROVE;
 160  0
                 flags[buttons.DISAPPROVE.ordinal()] = UserAction.ACTION_DISAPPROVE;
 161  
             }
 162  
             
 163  
             // should invoke WorkflowDocument.saveRoutingData(...).
 164  0
             flags[buttons.SAVE.ordinal()] = UserAction.ACTION_SAVE;
 165  0
             if (wfdoc.getPreviousNodeNames().size() > 0) {
 166  0
                 flags[buttons.RETURNTOPREVIOUS.ordinal()] = UserAction.ACTION_RETURN_TO_PREVIOUS;
 167  
             }
 168  
         }
 169  
         
 170  
         // this will never happen, but left code in case this gets figured out later
 171  
         // if allowed to execute save/approve and complete will both show
 172  0
         else if (wfdoc.isCompletionRequested()) {
 173  0
             flags[buttons.COMPLETE.ordinal()] = UserAction.ACTION_COMPLETE;
 174  0
             if (wfdoc.isBlanketApproveCapable()) {
 175  0
                 flags[buttons.BLANKETAPPROVE.ordinal()] = UserAction.ACTION_BLANKETAPPROVE;
 176  
             }
 177  
         }
 178  
         
 179  0
         if (wfdoc.isFYIRequested()) {
 180  0
             flags[buttons.FYI.ordinal()] = UserAction.ACTION_FYI;
 181  
         }
 182  
         
 183  0
         if (wfdoc.isRouteCapable()) {
 184  0
             flags[buttons.ROUTE.ordinal()] = UserAction.ACTION_ROUTE;
 185  0
             if (wfdoc.isBlanketApproveCapable()) {
 186  0
                 flags[buttons.BLANKETAPPROVE.ordinal()] = UserAction.ACTION_BLANKETAPPROVE;
 187  
             }
 188  
         }
 189  
         
 190  0
         if (wfdoc.isApprovalRequested() || wfdoc.isRouteCapable()) {
 191  0
             flags[buttons.SAVE.ordinal()] = UserAction.ACTION_SAVE;
 192  
         }
 193  
         
 194  0
         if (wfdoc.isCompletionRequested() || wfdoc.isRouteCapable()) {
 195  0
             flags[buttons.CANCEL.ordinal()] = UserAction.ACTION_CANCEL;
 196  
         }
 197  
 
 198  0
         for (int i = 0; i < flags.length; i++) {
 199  0
             if (flags[i] != null) {
 200  0
                 list.add(flags[i]);
 201  
             }
 202  
         }
 203  
 
 204  0
         return list;
 205  
     }
 206  
         
 207  
         public static boolean isEditable(EDLContext edlContext, List actions) {
 208  0
             boolean editable = false;
 209  0
             editable = listContainsItems(actions, UserAction.EDITABLE_ACTIONS);
 210  
             // reset editable flag to true if edoclite specifies <param name="alwaysEditable">true</param>
 211  0
             Document edlDom = EdlServiceLocator.getEDocLiteService().getDefinitionXml(edlContext.getEdocLiteAssociation());
 212  
             // use xpath to check for attribute value on Config param element.
 213  0
             XPath xpath = XPathFactory.newInstance().newXPath();
 214  0
             String xpathExpression = "//config/param[@name='alwaysEditable']"; 
 215  
             try {
 216  0
                 String match = (String) xpath.evaluate(xpathExpression, edlDom, XPathConstants.STRING);
 217  0
                 if (!StringUtils.isBlank(match) && match.equals("true")) {
 218  0
                     return true;
 219  
                 }
 220  0
             } catch (XPathExpressionException e) {
 221  0
                 throw new WorkflowRuntimeException("Unable to evaluate xpath expression " + xpathExpression, e);
 222  0
                 }
 223  
 
 224  0
             return editable;
 225  
         }
 226  
         
 227  
 
 228  
     public static void addActions(Document dom, Element documentState, List actions) {
 229  0
         Element actionsPossible = EDLXmlUtils.getOrCreateChildElement(documentState, "actionsPossible", true);
 230  0
         Iterator it = actions.iterator();
 231  0
         while (it.hasNext()) {
 232  0
             String action = it.next().toString();
 233  0
             Element actionElement = dom.createElement(action);
 234  
             // if we use string.xsl we can avoid doing this here
 235  
             // (unless for some reason we decide we want different titles)
 236  0
             if (!Character.isUpperCase(action.charAt(0))) {
 237  0
                 StringBuffer sb = new StringBuffer(action);
 238  0
                 sb.setCharAt(0, Character.toUpperCase(sb.charAt(0)));
 239  0
                 action = sb.toString();
 240  
             }
 241  0
             actionElement.setAttribute("title", action);
 242  0
             actionsPossible.appendChild(actionElement);
 243  0
         }
 244  
 
 245  0
         Element annotatable = EDLXmlUtils.getOrCreateChildElement(documentState, "annotatable", true);
 246  0
         annotatable.appendChild(dom.createTextNode(String.valueOf(isAnnotatable(actions))));
 247  0
     }
 248  
 
 249  
 
 250  
 
 251  
 
 252  
     public static boolean listContainsItems(List list, Object[] items) {
 253  0
         for (int i = 0; i < items.length; i++) {
 254  0
             if (list.contains(items[i])) return true;
 255  
         }
 256  0
         return false;
 257  
     }
 258  
 
 259  
     /**
 260  
      * Determines whether to display the annotation text box
 261  
      * Currently we will show the annotation box if ANY of the possible actions are
 262  
      * annotatable.
 263  
      * But what happens if we have an un-annotatable action?
 264  
      * Hey, why don't we just make all actions annotatable.
 265  
      * @param actions list of possible actions
 266  
      * @return whether to show the annotation text box
 267  
      */
 268  
     public static boolean isAnnotatable(List actions) {
 269  0
         return listContainsItems(actions, UserAction.ANNOTATABLE_ACTIONS);
 270  
     }
 271  
 
 272  
 }