001/**
002 * Copyright 2005-2016 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 */
016package org.kuali.rice.kew.rule;
017
018import org.apache.commons.lang.StringUtils;
019import org.kuali.rice.kew.api.KewApiConstants;
020import org.kuali.rice.kew.api.WorkflowRuntimeException;
021import org.kuali.rice.kew.api.extension.ExtensionDefinition;
022import org.kuali.rice.kew.api.identity.Id;
023import org.kuali.rice.kew.engine.RouteContext;
024import org.kuali.rice.kew.routeheader.DocumentContent;
025import org.kuali.rice.kew.rule.xmlrouting.GenericXMLRuleAttribute;
026import org.kuali.rice.kew.rule.xmlrouting.XPathHelper;
027import org.w3c.dom.Element;
028import org.w3c.dom.NodeList;
029import org.xml.sax.InputSource;
030
031import javax.xml.xpath.XPath;
032import javax.xml.xpath.XPathConstants;
033import javax.xml.xpath.XPathExpressionException;
034import java.io.StringReader;
035import java.util.ArrayList;
036import java.util.HashMap;
037import java.util.List;
038import 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 */
047public 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
053        private String idValue;
054        private Map paramMap = new HashMap();
055        private ExtensionDefinition extensionDefinition;
056
057        protected abstract String getAttributeElementName();
058
059        protected abstract Id resolveId(String id);
060
061        protected abstract String getIdName();
062
063        /**
064         * Returns qualified role names based on IDs in the XML. Each returned
065         * qualified Role contains a single ID.
066         * 
067         * @see org.kuali.rice.kew.rule.RoleAttribute#getQualifiedRoleNames(java.lang.String,
068         *      org.kuali.rice.kew.routeheader.DocumentContent)
069         */
070        public List<String> getQualifiedRoleNames(String roleName,
071                        DocumentContent documentContent) {
072                try {
073                        readConfiguration();
074                        String elementName = (String) getParamMap().get(XML_ELEMENT_LABEL);
075                        List<String> qualifiedRoleNames = new ArrayList<String>();
076                        XPath xPath = XPathHelper.newXPath();
077                        NodeList idNodes = (NodeList) xPath.evaluate("//"
078                                        + getAttributeElementName() + "/" + elementName,
079                                        documentContent.getDocument(), XPathConstants.NODESET);
080                        for (int index = 0; index < idNodes.getLength(); index++) {
081                                Element idElement = (Element) idNodes.item(index);
082                                String id = idElement.getTextContent();
083                                qualifiedRoleNames.add(id);
084                        }
085                        return qualifiedRoleNames;
086                } catch (XPathExpressionException e) {
087                        throw new WorkflowRuntimeException(
088                                        "Failed to evaulate XPath expression to find ids.", e);
089                }
090        }
091
092        /**
093         * Takes the given qualified role which contains an ID and returns a
094         * resolved role for the entity with that id.
095         * 
096         * @see org.kuali.rice.kew.rule.RoleAttribute#resolveQualifiedRole(org.kuali.rice.kew.engine.RouteContext,
097         *      java.lang.String, java.lang.String)
098         */
099        public ResolvedQualifiedRole resolveQualifiedRole(
100                        RouteContext routeContext, String roleName, String qualifiedRole) {
101                String roleNameLabel = (String) getParamMap().get(ROLE_NAME_LABEL);
102                if (roleNameLabel == null) {
103                        readConfiguration();
104                        roleNameLabel = (String) getParamMap().get(ROLE_NAME_LABEL);
105                }
106                ResolvedQualifiedRole resolvedRole = new ResolvedQualifiedRole();
107                resolvedRole.setQualifiedRoleLabel(roleNameLabel);
108                resolvedRole.getRecipients().add(resolveId(qualifiedRole));
109                return resolvedRole;
110        }
111
112        /**
113         * Generates XML containing the ID on this attribute.
114         * 
115         * @see org.kuali.rice.kew.rule.AbstractWorkflowAttribute#getDocContent()
116         */
117        @Override
118        public String getDocContent() {
119                readConfiguration();
120                if (!StringUtils.isBlank(getIdValue())) {
121                        String elementName = (String) getParamMap().get(XML_ELEMENT_LABEL);
122                        return "<" + getAttributeElementName() + "><" + elementName + ">"
123                                        + getIdValue() + "</" + elementName + "></"
124                                        + getAttributeElementName() + ">";
125                }
126                return "";
127        }
128
129        /**
130         * Reads any configured values in the XML of the RuleAttribute and adds them
131         * to the paramMap.
132         * 
133         */
134        protected void readConfiguration() {
135                String idInMap = (String) getParamMap().get(getIdName());
136                if (getIdValue() == null) {
137                        setIdValue(idInMap);
138                }
139                if (getIdValue() != null) {
140                        getParamMap().put(getIdName(), getIdValue());
141                }
142                if (extensionDefinition != null) {
143                        String xmlConfigData = extensionDefinition.getConfiguration().get(KewApiConstants.ATTRIBUTE_XML_CONFIG_DATA);
144                        if (!StringUtils.isBlank(xmlConfigData)) {
145                                XPath xPath = XPathHelper.newXPath();
146                                try {
147                                        String xmlElementLabel = xPath.evaluate("/configuration/"
148                                                        + XML_ELEMENT_LABEL, new InputSource(
149                                                        new StringReader(xmlConfigData)));
150                                        String roleNameLabel = xPath.evaluate("/configuration/"
151                                                        + ROLE_NAME_LABEL, new InputSource(
152                                                        new StringReader(xmlConfigData)));
153                                        if (!StringUtils.isBlank(xmlElementLabel)) {
154                                                getParamMap().put(XML_ELEMENT_LABEL, xmlElementLabel);
155                                        }
156                                        if (!StringUtils.isBlank(roleNameLabel)) {
157                                                getParamMap().put(ROLE_NAME_LABEL, roleNameLabel);
158                                        }
159
160                                } catch (XPathExpressionException e) {
161                                        throw new WorkflowRuntimeException(
162                                                        "Failed to locate Rule Attribute configuration.");
163                                }
164                        }
165                }
166                // setup default values if none were defined in XML
167                if (StringUtils.isBlank((String) getParamMap().get(XML_ELEMENT_LABEL))) {
168                        getParamMap().put(XML_ELEMENT_LABEL, getIdName());
169                }
170                if (getParamMap().get(ROLE_NAME_LABEL) == null) {
171                        getParamMap().put(ROLE_NAME_LABEL, "");
172                }
173        }
174
175        public String getIdValue() {
176                return this.idValue;
177        }
178
179        public void setIdValue(String idValue) {
180                this.idValue = idValue;
181        }
182
183        public Map getParamMap() {
184                return paramMap;
185        }
186
187        public void setParamMap(Map paramMap) {
188                this.paramMap = paramMap;
189        }
190
191        public void setExtensionDefinition(ExtensionDefinition extensionDefinition) {
192                this.extensionDefinition = extensionDefinition;
193        }
194
195}