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