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