Java tutorial
/** * Copyright 2005-2014 The Kuali Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ecl2.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kuali.rice.edl.impl.components; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.kuali.rice.core.api.util.RiceConstants; import org.kuali.rice.core.api.util.xml.XmlJotter; import org.kuali.rice.coreservice.framework.CoreFrameworkServiceLocator; import org.kuali.rice.edl.impl.EDLContext; import org.kuali.rice.edl.impl.EDLModelComponent; import org.kuali.rice.edl.impl.EDLXmlUtils; import org.kuali.rice.edl.impl.RequestParser; import org.kuali.rice.edl.impl.UserAction; import org.kuali.rice.edl.impl.service.EdlServiceLocator; import org.kuali.rice.kew.api.KewApiServiceLocator; import org.kuali.rice.kew.api.WorkflowDocument; import org.kuali.rice.kew.api.WorkflowRuntimeException; import org.kuali.rice.kew.api.document.node.RouteNodeInstance; import org.kuali.rice.kew.api.exception.WorkflowException; import org.kuali.rice.kew.api.KewApiConstants; import org.kuali.rice.krad.util.KRADConstants; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Generates document state based on the workflow document in session. * * @author Kuali Rice Team (rice.collab@kuali.org) * */ public class WorkflowDocumentState implements EDLModelComponent { private static final Logger LOG = Logger.getLogger(WorkflowDocumentState.class); // The order the enum values are listed determines the order the buttons appear on the screen private enum buttons { ACKNOWLEDGE, BLANKETAPPROVE, ROUTE, SAVE, COMPLETE, APPROVE, DISAPPROVE, RETURNTOPREVIOUS, FYI, CANCEL }; public void updateDOM(Document dom, Element configElement, EDLContext edlContext) { try { Element documentState = EDLXmlUtils.getDocumentStateElement(dom); Element dateTime = EDLXmlUtils.getOrCreateChildElement(documentState, "dateTime", true); dateTime.appendChild( dom.createTextNode(RiceConstants.getDefaultDateAndTimeFormat().format(new Date()))); Element definition = EDLXmlUtils.getOrCreateChildElement(documentState, "definition", true); definition.appendChild(dom.createTextNode(edlContext.getEdocLiteAssociation().getDefinition())); Element docType = EDLXmlUtils.getOrCreateChildElement(documentState, "docType", true); docType.appendChild(dom.createTextNode(edlContext.getEdocLiteAssociation().getEdlName())); Element style = EDLXmlUtils.getOrCreateChildElement(documentState, "style", true); String styleName = edlContext.getEdocLiteAssociation().getStyle(); if (styleName == null) { styleName = "Default"; } style.appendChild(dom.createTextNode(styleName)); Element showAttachments = EDLXmlUtils.getOrCreateChildElement(documentState, "showAttachments", true); boolean showConstants = CoreFrameworkServiceLocator.getParameterService().getParameterValueAsBoolean( KewApiConstants.KEW_NAMESPACE, KRADConstants.DetailTypes.ALL_DETAIL_TYPE, KewApiConstants.SHOW_ATTACHMENTS_IND); showAttachments.appendChild(dom.createTextNode(Boolean.valueOf(showConstants).toString())); WorkflowDocument document = (WorkflowDocument) edlContext.getRequestParser() .getAttribute(RequestParser.WORKFLOW_DOCUMENT_SESSION_KEY); boolean documentEditable = false; if (document != null) { List<String> validActions = determineValidActions(document); documentEditable = isEditable(edlContext, validActions); edlContext.getTransformer().setParameter("readOnly", String.valueOf(documentEditable)); addActions(dom, documentState, validActions); boolean isAnnotatable = isAnnotatable(validActions); EDLXmlUtils.createTextElementOnParent(documentState, "annotatable", String.valueOf(isAnnotatable)); EDLXmlUtils.createTextElementOnParent(documentState, "docId", document.getDocumentId()); Element workflowDocumentStatus = EDLXmlUtils.getOrCreateChildElement(documentState, "workflowDocumentState", true); EDLXmlUtils.createTextElementOnParent(workflowDocumentStatus, "status", document.getStatus().getLabel()); EDLXmlUtils.createTextElementOnParent(workflowDocumentStatus, "createDate", RiceConstants.getDefaultDateAndTimeFormat().format(document.getDateCreated().toDate())); List<String> nodeNames = document.getPreviousNodeNames(); if (nodeNames.size() > 0) { Element previousNodes = EDLXmlUtils.getOrCreateChildElement(documentState, "previousNodes", true); // don't include LAST node (where the document is currently...don't want to return to current location) for (int i = 0; i < nodeNames.size(); i++) { EDLXmlUtils.createTextElementOnParent(previousNodes, "node", nodeNames.get(i)); } } List<RouteNodeInstance> routeNodeInstances = KewApiServiceLocator.getWorkflowDocumentService() .getCurrentRouteNodeInstances(document.getDocumentId()); for (RouteNodeInstance currentNode : routeNodeInstances) { EDLXmlUtils.createTextElementOnParent(documentState, "currentNodeName", currentNode.getName()); } } Element editable = EDLXmlUtils.getOrCreateChildElement(documentState, "editable", true); editable.appendChild(dom.createTextNode(String.valueOf(documentEditable))); // display the buttons EDLXmlUtils.createTextElementOnParent(documentState, "actionable", "true"); List globalErrors = (List) edlContext.getRequestParser().getAttribute(RequestParser.GLOBAL_ERRORS_KEY); List globalMessages = (List) edlContext.getRequestParser() .getAttribute(RequestParser.GLOBAL_MESSAGES_KEY); Map<String, String> globalFieldErrors = (Map) edlContext.getRequestParser() .getAttribute(RequestParser.GLOBAL_FIELD_ERRORS_KEY); EDLXmlUtils.addErrorsAndMessagesToDocument(dom, globalErrors, globalMessages, globalFieldErrors); if (LOG.isDebugEnabled()) { LOG.debug("Transforming dom " + XmlJotter.jotNode(dom, true)); } } catch (Exception e) { throw new WorkflowRuntimeException(e); } } public static List<String> determineValidActions(WorkflowDocument wfdoc) throws WorkflowException { String[] flags = new String[10]; List<String> list = new ArrayList<String>(); if (wfdoc == null) { list.add(UserAction.ACTION_CREATE); return list; } if (wfdoc.isAcknowledgeRequested()) { flags[buttons.ACKNOWLEDGE.ordinal()] = UserAction.ACTION_ACKNOWLEDGE; } if (wfdoc.isApprovalRequested()) { if (wfdoc.isBlanketApproveCapable()) { flags[buttons.BLANKETAPPROVE.ordinal()] = UserAction.ACTION_BLANKETAPPROVE; } if (!wfdoc.isSaved()) { flags[buttons.APPROVE.ordinal()] = UserAction.ACTION_APPROVE; flags[buttons.DISAPPROVE.ordinal()] = UserAction.ACTION_DISAPPROVE; } // should invoke WorkflowDocument.saveRoutingData(...). flags[buttons.SAVE.ordinal()] = UserAction.ACTION_SAVE; if (wfdoc.getPreviousNodeNames().size() > 0) { flags[buttons.RETURNTOPREVIOUS.ordinal()] = UserAction.ACTION_RETURN_TO_PREVIOUS; } } // this will never happen, but left code in case this gets figured out later // if allowed to execute save/approve and complete will both show else if (wfdoc.isCompletionRequested()) { flags[buttons.COMPLETE.ordinal()] = UserAction.ACTION_COMPLETE; if (wfdoc.isBlanketApproveCapable()) { flags[buttons.BLANKETAPPROVE.ordinal()] = UserAction.ACTION_BLANKETAPPROVE; } } if (wfdoc.isFYIRequested()) { flags[buttons.FYI.ordinal()] = UserAction.ACTION_FYI; } if (wfdoc.isRouteCapable()) { flags[buttons.ROUTE.ordinal()] = UserAction.ACTION_ROUTE; if (wfdoc.isBlanketApproveCapable()) { flags[buttons.BLANKETAPPROVE.ordinal()] = UserAction.ACTION_BLANKETAPPROVE; } } if (wfdoc.isApprovalRequested() || wfdoc.isRouteCapable()) { flags[buttons.SAVE.ordinal()] = UserAction.ACTION_SAVE; } if (wfdoc.isCompletionRequested() || wfdoc.isRouteCapable()) { flags[buttons.CANCEL.ordinal()] = UserAction.ACTION_CANCEL; } for (int i = 0; i < flags.length; i++) { if (flags[i] != null) { list.add(flags[i]); } } return list; } public static boolean isEditable(EDLContext edlContext, List actions) { boolean editable = false; editable = listContainsItems(actions, UserAction.EDITABLE_ACTIONS); // reset editable flag to true if edoclite specifies <param name="alwaysEditable">true</param> Document edlDom = EdlServiceLocator.getEDocLiteService() .getDefinitionXml(edlContext.getEdocLiteAssociation()); // use xpath to check for attribute value on Config param element. XPath xpath = edlContext.getXpath(); String xpathExpression = "//config/param[@name='alwaysEditable']"; try { String match = (String) xpath.evaluate(xpathExpression, edlDom, XPathConstants.STRING); if (!StringUtils.isBlank(match) && match.equals("true")) { return true; } } catch (XPathExpressionException e) { throw new WorkflowRuntimeException("Unable to evaluate xpath expression " + xpathExpression, e); } return editable; } public static void addActions(Document dom, Element documentState, List actions) { Element actionsPossible = EDLXmlUtils.getOrCreateChildElement(documentState, "actionsPossible", true); Iterator it = actions.iterator(); while (it.hasNext()) { String action = it.next().toString(); Element actionElement = dom.createElement(action); // if we use string.xsl we can avoid doing this here // (unless for some reason we decide we want different titles) if (!Character.isUpperCase(action.charAt(0))) { StringBuffer sb = new StringBuffer(action); sb.setCharAt(0, Character.toUpperCase(sb.charAt(0))); action = sb.toString(); } actionElement.setAttribute("title", action); actionsPossible.appendChild(actionElement); } Element annotatable = EDLXmlUtils.getOrCreateChildElement(documentState, "annotatable", true); annotatable.appendChild(dom.createTextNode(String.valueOf(isAnnotatable(actions)))); } public static boolean listContainsItems(List list, Object[] items) { for (int i = 0; i < items.length; i++) { if (list.contains(items[i])) return true; } return false; } /** * Determines whether to display the annotation text box * Currently we will show the annotation box if ANY of the possible actions are * annotatable. * But what happens if we have an un-annotatable action? * Hey, why don't we just make all actions annotatable. * @param actions list of possible actions * @return whether to show the annotation text box */ public static boolean isAnnotatable(List actions) { return listContainsItems(actions, UserAction.ANNOTATABLE_ACTIONS); } }