001 /** 002 * Copyright 2005-2014 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.kew.rule; 017 018 import org.apache.commons.lang.StringUtils; 019 import org.kuali.rice.kew.api.KewApiConstants; 020 import org.kuali.rice.kew.api.WorkflowRuntimeException; 021 import org.kuali.rice.kew.api.extension.ExtensionDefinition; 022 import org.kuali.rice.kew.api.identity.Id; 023 import org.kuali.rice.kew.engine.RouteContext; 024 import org.kuali.rice.kew.routeheader.DocumentContent; 025 import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute; 026 import org.kuali.rice.kew.rule.xmlrouting.XPathHelper; 027 import org.w3c.dom.Element; 028 import org.w3c.dom.NodeList; 029 import org.xml.sax.InputSource; 030 031 import javax.xml.xpath.XPath; 032 import javax.xml.xpath.XPathConstants; 033 import javax.xml.xpath.XPathExpressionException; 034 import java.io.StringReader; 035 import java.util.ArrayList; 036 import java.util.HashMap; 037 import java.util.List; 038 import java.util.Map; 039 040 /** 041 * A generic Role Attribute superclass that can be used to route to an ID. Can 042 * take as configuration the label to use for the element name in the XML. This 043 * allows for re-use of this component in different contexts. 044 * 045 * @author Kuali Rice Team (rice.collab@kuali.org) 046 */ 047 public abstract class AbstractIdRoleAttribute extends AbstractRoleAttribute 048 implements GenericXMLRuleAttribute { 049 050 private static final String XML_ELEMENT_LABEL = "xmlElementLabel"; 051 private static final String ROLE_NAME_LABEL = "roleNameLabel"; 052 private static final String GROUP_TOGETHER_LABEL = "groupTogether"; 053 private static final String STRING_ID_SEPERATOR = ","; 054 055 private String idValue; 056 private Map paramMap = new HashMap(); 057 private ExtensionDefinition extensionDefinition; 058 059 protected abstract String getAttributeElementName(); 060 061 protected abstract Id resolveId(String id); 062 063 protected abstract String getIdName(); 064 065 /** 066 * Returns qualified role names based on IDs in the XML. Each returned 067 * qualified Role contains a single ID. 068 * 069 * @see org.kuali.rice.kew.rule.RoleAttribute#getQualifiedRoleNames(java.lang.String, 070 * org.kuali.rice.kew.routeheader.DocumentContent) 071 */ 072 public List<String> getQualifiedRoleNames(String roleName, 073 DocumentContent documentContent) { 074 try { 075 readConfiguration(); 076 String elementName = (String) getParamMap().get(XML_ELEMENT_LABEL); 077 List<String> qualifiedRoleNames = new ArrayList<String>(); 078 XPath xPath = XPathHelper.newXPath(); 079 NodeList idNodes = (NodeList) xPath.evaluate("//" 080 + getAttributeElementName() + "/" + elementName, 081 documentContent.getDocument(), XPathConstants.NODESET); 082 List<String> qualifiedRoleIds = new ArrayList<String>(); //used only for groupTogether parsing 083 for (int index = 0; index < idNodes.getLength(); index++) { 084 Element idElement = (Element) idNodes.item(index); 085 String id = idElement.getTextContent(); 086 if(isGroupTogetherRole()) { 087 qualifiedRoleIds.add(id); 088 } else { 089 qualifiedRoleNames.add(id); 090 } 091 } 092 if(isGroupTogetherRole()){ 093 qualifiedRoleNames.add(StringUtils.join(qualifiedRoleIds, STRING_ID_SEPERATOR)); 094 } 095 return qualifiedRoleNames; 096 } catch (XPathExpressionException e) { 097 throw new WorkflowRuntimeException( 098 "Failed to evaulate XPath expression to find ids.", e); 099 } 100 } 101 102 private boolean isGroupTogetherRole(){ 103 String value = (String) getParamMap().get(GROUP_TOGETHER_LABEL); 104 if(StringUtils.isNotBlank(value) && value.equalsIgnoreCase("true")){ 105 return true; 106 } 107 return false; 108 } 109 110 /** 111 * Takes the given qualified role which contains an ID and returns a 112 * resolved role for the entity with that id. 113 * 114 * @see org.kuali.rice.kew.rule.RoleAttribute#resolveQualifiedRole(org.kuali.rice.kew.engine.RouteContext, 115 * java.lang.String, java.lang.String) 116 */ 117 public ResolvedQualifiedRole resolveQualifiedRole( 118 RouteContext routeContext, String roleName, String qualifiedRole) { 119 String roleNameLabel = (String) getParamMap().get(ROLE_NAME_LABEL); 120 if (roleNameLabel == null) { 121 readConfiguration(); 122 roleNameLabel = (String) getParamMap().get(ROLE_NAME_LABEL); 123 } 124 125 String groupTogetherLabel = (String) getParamMap().get(GROUP_TOGETHER_LABEL); 126 if (groupTogetherLabel == null) { 127 readConfiguration(); 128 groupTogetherLabel = (String) getParamMap().get(GROUP_TOGETHER_LABEL); 129 } 130 131 ResolvedQualifiedRole resolvedRole = new ResolvedQualifiedRole(); 132 resolvedRole.setQualifiedRoleLabel(roleNameLabel); 133 134 if(isGroupTogetherRole()){ 135 String[] qualifiedRoleIds = StringUtils.split(qualifiedRole, STRING_ID_SEPERATOR); 136 for (String qId : qualifiedRoleIds) { 137 resolvedRole.getRecipients().add(resolveId(qId)); 138 } 139 }else{ 140 resolvedRole.getRecipients().add(resolveId(qualifiedRole)); 141 } 142 return resolvedRole; 143 } 144 145 /** 146 * Generates XML containing the ID on this attribute. 147 * 148 * @see org.kuali.rice.kew.rule.AbstractWorkflowAttribute#getDocContent() 149 */ 150 @Override 151 public String getDocContent() { 152 readConfiguration(); 153 if (!StringUtils.isBlank(getIdValue())) { 154 String elementName = (String) getParamMap().get(XML_ELEMENT_LABEL); 155 return "<" + getAttributeElementName() + "><" + elementName + ">" 156 + getIdValue() + "</" + elementName + "></" 157 + getAttributeElementName() + ">"; 158 } 159 return ""; 160 } 161 162 /** 163 * Reads any configured values in the XML of the RuleAttribute and adds them 164 * to the paramMap. 165 * 166 */ 167 protected void readConfiguration() { 168 String idInMap = (String) getParamMap().get(getIdName()); 169 if (getIdValue() == null) { 170 setIdValue(idInMap); 171 } 172 if (getIdValue() != null) { 173 getParamMap().put(getIdName(), getIdValue()); 174 } 175 if (extensionDefinition != null) { 176 String xmlConfigData = extensionDefinition.getConfiguration().get(KewApiConstants.ATTRIBUTE_XML_CONFIG_DATA); 177 if (!StringUtils.isBlank(xmlConfigData)) { 178 XPath xPath = XPathHelper.newXPath(); 179 try { 180 String xmlElementLabel = xPath.evaluate("/configuration/" 181 + XML_ELEMENT_LABEL, new InputSource( 182 new StringReader(xmlConfigData))); 183 String roleNameLabel = xPath.evaluate("/configuration/" 184 + ROLE_NAME_LABEL, new InputSource( 185 new StringReader(xmlConfigData))); 186 String groupTogetherLabel = xPath.evaluate("/configuration/" 187 + GROUP_TOGETHER_LABEL, new InputSource( 188 new StringReader(xmlConfigData))); 189 if (!StringUtils.isBlank(xmlElementLabel)) { 190 getParamMap().put(XML_ELEMENT_LABEL, xmlElementLabel); 191 } 192 if (!StringUtils.isBlank(roleNameLabel)) { 193 getParamMap().put(ROLE_NAME_LABEL, roleNameLabel); 194 } 195 if (!StringUtils.isBlank(groupTogetherLabel)) { 196 getParamMap().put(GROUP_TOGETHER_LABEL, groupTogetherLabel); 197 } 198 199 } catch (XPathExpressionException e) { 200 throw new WorkflowRuntimeException( 201 "Failed to locate Rule Attribute configuration."); 202 } 203 } 204 } 205 // setup default values if none were defined in XML 206 if (StringUtils.isBlank((String) getParamMap().get(XML_ELEMENT_LABEL))) { 207 getParamMap().put(XML_ELEMENT_LABEL, getIdName()); 208 } 209 if (getParamMap().get(ROLE_NAME_LABEL) == null) { 210 getParamMap().put(ROLE_NAME_LABEL, ""); 211 } 212 if (StringUtils.isBlank((String) getParamMap().get(GROUP_TOGETHER_LABEL))) { 213 getParamMap().put(GROUP_TOGETHER_LABEL, "false"); 214 } 215 } 216 217 public String getIdValue() { 218 return this.idValue; 219 } 220 221 public void setIdValue(String idValue) { 222 this.idValue = idValue; 223 } 224 225 public Map getParamMap() { 226 return paramMap; 227 } 228 229 public void setParamMap(Map paramMap) { 230 this.paramMap = paramMap; 231 } 232 233 public void setExtensionDefinition(ExtensionDefinition extensionDefinition) { 234 this.extensionDefinition = extensionDefinition; 235 } 236 237 }