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.kns.workflow; 017 018import java.util.ArrayList; 019import java.util.List; 020import java.util.Map; 021import java.util.Properties; 022 023import javax.xml.xpath.XPath; 024import javax.xml.xpath.XPathExpressionException; 025import javax.xml.xpath.XPathFactory; 026 027import org.apache.commons.lang.StringUtils; 028import org.kuali.rice.kew.engine.RouteContext; 029import org.kuali.rice.kew.rule.xmlrouting.WorkflowFunctionResolver; 030import org.kuali.rice.kew.rule.xmlrouting.WorkflowNamespaceContext; 031import org.kuali.rice.kns.util.FieldUtils; 032import org.kuali.rice.kns.web.ui.Field; 033import org.kuali.rice.kns.web.ui.Row; 034import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 035import org.kuali.rice.krad.util.KRADConstants; 036import org.kuali.rice.krad.util.KRADPropertyConstants; 037import org.kuali.rice.krad.util.UrlFactory; 038import org.w3c.dom.Document; 039 040/** 041 * @author Kuali Rice Team (rice.collab@kuali.org) 042 * 043 * @deprecated Only used by KNS classes, no replacement. 044 */ 045@Deprecated 046public final class WorkflowUtils { 047 private static final String XPATH_ROUTE_CONTEXT_KEY = "_xpathKey"; 048 public static final String XSTREAM_SAFE_PREFIX = "wf:xstreamsafe('"; 049 public static final String XSTREAM_SAFE_SUFFIX = "')"; 050 public static final String XSTREAM_MATCH_ANYWHERE_PREFIX = "//"; 051 public static final String XSTREAM_MATCH_RELATIVE_PREFIX = "./"; 052 053 private WorkflowUtils() { 054 throw new UnsupportedOperationException("do not call"); 055 } 056 057 /** 058 * 059 * This method sets up the XPath with the correct workflow namespace and resolver initialized. This ensures that the XPath 060 * statements can use required workflow functions as part of the XPath statements. 061 * 062 * @param document - document 063 * @return a fully initialized XPath instance that has access to the workflow resolver and namespace. 064 * 065 */ 066 public final static XPath getXPath(Document document) { 067 XPath xpath = getXPath(RouteContext.getCurrentRouteContext()); 068 xpath.setNamespaceContext(new WorkflowNamespaceContext()); 069 WorkflowFunctionResolver resolver = new WorkflowFunctionResolver(); 070 resolver.setXpath(xpath); 071 resolver.setRootNode(document); 072 xpath.setXPathFunctionResolver(resolver); 073 return xpath; 074 } 075 076 public final static XPath getXPath(RouteContext routeContext) { 077 if (routeContext == null) { 078 return XPathFactory.newInstance().newXPath(); 079 } 080 if (!routeContext.getParameters().containsKey(XPATH_ROUTE_CONTEXT_KEY)) { 081 routeContext.getParameters().put(XPATH_ROUTE_CONTEXT_KEY, XPathFactory.newInstance().newXPath()); 082 } 083 return (XPath) routeContext.getParameters().get(XPATH_ROUTE_CONTEXT_KEY); 084 } 085 086 /** 087 * This method will do a simple XPath.evaluate, while wrapping your xpathExpression with the xstreamSafe function. It assumes a 088 * String result, and will return such. If an XPathExpressionException is thrown, this will be re-thrown within a 089 * RuntimeException. 090 * 091 * @param xpath A correctly initialized XPath instance. 092 * @param xpathExpression Your XPath Expression that needs to be wrapped in an xstreamSafe wrapper and run. 093 * @param item The document contents you will be searching within. 094 * @return The string value of the xpath.evaluate(). 095 */ 096 public static final String xstreamSafeEval(XPath xpath, String xpathExpression, Object item) { 097 String xstreamSafeXPath = xstreamSafeXPath(xpathExpression); 098 String evalResult = ""; 099 try { 100 evalResult = xpath.evaluate(xstreamSafeXPath, item); 101 } 102 catch (XPathExpressionException e) { 103 throw new RuntimeException("XPathExpressionException occurred on xpath: " + xstreamSafeXPath, e); 104 } 105 return evalResult; 106 } 107 108 /** 109 * This method wraps the passed-in XPath expression in XStream Safe wrappers, so that XStream generated reference links will be 110 * handled correctly. 111 * 112 * @param xpathExpression The XPath Expression you wish to use. 113 * @return Your XPath Expression wrapped in the XStreamSafe wrapper. 114 */ 115 public static final String xstreamSafeXPath(String xpathExpression) { 116 return new StringBuilder(XSTREAM_SAFE_PREFIX).append(xpathExpression).append(XSTREAM_SAFE_SUFFIX).toString(); 117 } 118 119 /** 120 * This method returns a label from the data dictionary service 121 * 122 * @param businessObjectClass - class where the label should come from 123 * @param attributeName - name of the attribute you need the label for 124 * @return the label from the data dictionary for the given Class and attributeName or null if not found 125 */ 126 public static final String getBusinessObjectAttributeLabel(Class businessObjectClass, String attributeName) { 127 return KRADServiceLocatorWeb.getDataDictionaryService().getAttributeLabel(businessObjectClass, attributeName); 128 } 129 130 131 /** 132 * This method builds a workflow-lookup-screen Row of type TEXT, with no quickfinder/lookup. 133 * 134 * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber. 135 * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for 136 * Account.accountNumber. 137 * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This 138 * key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so 139 * everything links up correctly. 140 * @return A populated and ready-to-use workflow lookupable.Row. 141 */ 142 public static Row buildTextRow(Class propertyClass, String boPropertyName, String workflowPropertyKey) { 143 if (propertyClass == null) { 144 throw new IllegalArgumentException("Method parameter 'propertyClass' was passed a NULL value."); 145 } 146 if (StringUtils.isBlank(boPropertyName)) { 147 throw new IllegalArgumentException("Method parameter 'boPropertyName' was passed a NULL or blank value."); 148 } 149 if (StringUtils.isBlank(workflowPropertyKey)) { 150 throw new IllegalArgumentException("Method parameter 'workflowPropertyKey' was passed a NULL or blank value."); 151 } 152 List<Field> fields = new ArrayList<Field>(); 153 Field field; 154 field = FieldUtils.getPropertyField(propertyClass, boPropertyName, false); 155 fields.add(field); 156 return new Row(fields); 157 } 158 159 /** 160 * This method builds a workflow-lookup-screen Row of type TEXT, with the attached lookup icon and functionality. 161 * 162 * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber. 163 * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for 164 * Account.accountNumber. 165 * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This 166 * key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so 167 * everything links up correctly. 168 * @return A populated and ready-to-use workflow lookupable.Row, which includes both the property field and the lookup icon. 169 */ 170 public static Row buildTextRowWithLookup(Class propertyClass, String boPropertyName, String workflowPropertyKey) { 171 return buildTextRowWithLookup(propertyClass, boPropertyName, workflowPropertyKey, null); 172 } 173 174 /** 175 * This method builds a workflow-lookup-screen Row of type TEXT, with the attached lookup icon and functionality. 176 * 177 * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber. 178 * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for 179 * Account.accountNumber. 180 * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This 181 * key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so 182 * everything links up correctly. 183 * @param fieldConversionsByBoPropertyName A list of extra field conversions where the key is the business object property name 184 * and the value is the workflow property key 185 * @return A populated and ready-to-use workflow lookupable.Row, which includes both the property field and the lookup icon. 186 */ 187 public static Row buildTextRowWithLookup(Class propertyClass, String boPropertyName, String workflowPropertyKey, Map fieldConversionsByBoPropertyName) { 188 if (propertyClass == null) { 189 throw new IllegalArgumentException("Method parameter 'propertyClass' was passed a NULL value."); 190 } 191 if (StringUtils.isBlank(boPropertyName)) { 192 throw new IllegalArgumentException("Method parameter 'boPropertyName' was passed a NULL or blank value."); 193 } 194 if (StringUtils.isBlank(workflowPropertyKey)) { 195 throw new IllegalArgumentException("Method parameter 'workflowPropertyKey' was passed a NULL or blank value."); 196 } 197 Field field; 198 field = FieldUtils.getPropertyField(propertyClass, boPropertyName, false); 199 200 List<Field> fields = new ArrayList<Field>(); 201 fields.add(field); 202 return new Row(fields); 203 } 204 205 /** 206 * This method builds a workflow-lookup-screen Row of type DROPDOWN. 207 * 208 * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber. 209 * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for 210 * Account.accountNumber. 211 * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This 212 * key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so 213 * everything links up correctly. 214 * @param optionMap The map of value, text pairs that will be used to constuct the dropdown list. 215 * @return A populated and ready-to-use workflow lookupable.Row. 216 */ 217 public static Row buildDropdownRow(Class propertyClass, String boPropertyName, String workflowPropertyKey, Map<String, String> optionMap, boolean addBlankRow) { 218 if (propertyClass == null) { 219 throw new IllegalArgumentException("Method parameter 'propertyClass' was passed a NULL value."); 220 } 221 if (StringUtils.isBlank(boPropertyName)) { 222 throw new IllegalArgumentException("Method parameter 'boPropertyName' was passed a NULL or blank value."); 223 } 224 if (StringUtils.isBlank(workflowPropertyKey)) { 225 throw new IllegalArgumentException("Method parameter 'workflowPropertyKey' was passed a NULL or blank value."); 226 } 227 if (optionMap == null) { 228 throw new IllegalArgumentException("Method parameter 'optionMap' was passed a NULL value."); 229 } 230 List<Field> fields = new ArrayList<Field>(); 231 Field field; 232 field = FieldUtils.getPropertyField(propertyClass, boPropertyName, false); 233 fields.add(field); 234 return new Row(fields); 235 } 236}