001 /**
002 * Copyright 2005-2013 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 }