View Javadoc

1   /*
2    * Copyright 2007 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kns.workflow;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.Map;
21  import java.util.Properties;
22  
23  import javax.xml.xpath.XPath;
24  import javax.xml.xpath.XPathExpressionException;
25  import javax.xml.xpath.XPathFactory;
26  
27  import org.apache.commons.lang.StringUtils;
28  import org.kuali.rice.kew.engine.RouteContext;
29  import org.kuali.rice.kew.rule.xmlrouting.WorkflowFunctionResolver;
30  import org.kuali.rice.kew.rule.xmlrouting.WorkflowNamespaceContext;
31  import org.kuali.rice.kns.service.KNSServiceLocator;
32  import org.kuali.rice.kns.util.FieldUtils;
33  import org.kuali.rice.kns.util.KNSConstants;
34  import org.kuali.rice.kns.util.KNSPropertyConstants;
35  import org.kuali.rice.kns.util.UrlFactory;
36  import org.kuali.rice.kns.web.ui.Field;
37  import org.kuali.rice.kns.web.ui.Row;
38  import org.w3c.dom.Document;
39  
40  
41  public class WorkflowUtils {
42      private static final String XPATH_ROUTE_CONTEXT_KEY = "_xpathKey";
43      public static final String XSTREAM_SAFE_PREFIX = "wf:xstreamsafe('";
44      public static final String XSTREAM_SAFE_SUFFIX = "')";
45      public static final String XSTREAM_MATCH_ANYWHERE_PREFIX = "//";
46      public static final String XSTREAM_MATCH_RELATIVE_PREFIX = "./";
47  
48      /**
49       *
50       * This method sets up the XPath with the correct workflow namespace and resolver initialized. This ensures that the XPath
51       * statements can use required workflow functions as part of the XPath statements.
52       *
53       * @param document - document
54       * @return a fully initialized XPath instance that has access to the workflow resolver and namespace.
55       *
56       */
57      public final static XPath getXPath(Document document) {
58          XPath xpath = getXPath(RouteContext.getCurrentRouteContext());
59          xpath.setNamespaceContext(new WorkflowNamespaceContext());
60          WorkflowFunctionResolver resolver = new WorkflowFunctionResolver();
61          resolver.setXpath(xpath);
62          resolver.setRootNode(document);
63          xpath.setXPathFunctionResolver(resolver);
64          return xpath;
65      }
66  
67      public final static XPath getXPath(RouteContext routeContext) {
68          if (routeContext == null) {
69              return XPathFactory.newInstance().newXPath();
70          }
71          if (!routeContext.getParameters().containsKey(XPATH_ROUTE_CONTEXT_KEY)) {
72              routeContext.getParameters().put(XPATH_ROUTE_CONTEXT_KEY, XPathFactory.newInstance().newXPath());
73          }
74          return (XPath) routeContext.getParameters().get(XPATH_ROUTE_CONTEXT_KEY);
75      }
76  
77      /**
78       * This method will do a simple XPath.evaluate, while wrapping your xpathExpression with the xstreamSafe function. It assumes a
79       * String result, and will return such. If an XPathExpressionException is thrown, this will be re-thrown within a
80       * RuntimeException.
81       *
82       * @param xpath A correctly initialized XPath instance.
83       * @param xpathExpression Your XPath Expression that needs to be wrapped in an xstreamSafe wrapper and run.
84       * @param item The document contents you will be searching within.
85       * @return The string value of the xpath.evaluate().
86       */
87      public static final String xstreamSafeEval(XPath xpath, String xpathExpression, Object item) {
88          String xstreamSafeXPath = xstreamSafeXPath(xpathExpression);
89          String evalResult = "";
90          try {
91              evalResult = xpath.evaluate(xstreamSafeXPath, item);
92          }
93          catch (XPathExpressionException e) {
94              throw new RuntimeException("XPathExpressionException occurred on xpath: " + xstreamSafeXPath, e);
95          }
96          return evalResult;
97      }
98  
99      /**
100      * This method wraps the passed-in XPath expression in XStream Safe wrappers, so that XStream generated reference links will be
101      * handled correctly.
102      *
103      * @param xpathExpression The XPath Expression you wish to use.
104      * @return Your XPath Expression wrapped in the XStreamSafe wrapper.
105      */
106     public static final String xstreamSafeXPath(String xpathExpression) {
107         return new StringBuilder(XSTREAM_SAFE_PREFIX).append(xpathExpression).append(XSTREAM_SAFE_SUFFIX).toString();
108     }
109 
110     /**
111      * This method is for use by WorkflowLookupableImpl and WorkflowAttribute implementations to derive the fieldHelpUrl for use on
112      * org.kuali.rice.kns.web.ui.Fieldss.
113      *
114      * @param field The kuali field that we need to derive a help url for. @ return Returns the help url for the field.
115      */
116     public static String getHelpUrl(org.kuali.rice.kns.web.ui.Field field) {
117         Properties params = new Properties();
118         params.put(KNSConstants.DISPATCH_REQUEST_PARAMETER, "getAttributeHelpText");
119         params.put(KNSConstants.BUSINESS_OBJECT_CLASS_ATTRIBUTE, field.getBusinessObjectClassName());
120         params.put(KNSPropertyConstants.ATTRIBUTE_NAME, field.getPropertyName());
121         String baseUrl = KNSServiceLocator.getRiceApplicationConfigurationMediationService().getBaseHelpUrl(field.getBusinessObjectClassName());
122         if (baseUrl == null) {
123         	return null;
124         }
125         return UrlFactory.parameterizeUrl(baseUrl, params);
126     }
127 
128     /**
129      * This method returns a label from the data dictionary service
130      *
131      * @param businessObjectClass - class where the label should come from
132      * @param attributeName - name of the attribute you need the label for
133      * @return the label from the data dictionary for the given Class and attributeName or null if not found
134      */
135     public static final String getBusinessObjectAttributeLabel(Class businessObjectClass, String attributeName) {
136         return KNSServiceLocator.getDataDictionaryService().getAttributeLabel(businessObjectClass, attributeName);
137     }
138 
139 
140     /**
141      * This method builds a workflow-lookup-screen Row of type TEXT, with no quickfinder/lookup.
142      *
143      * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber.
144      * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for
145      *        Account.accountNumber.
146      * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This
147      *        key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so
148      *        everything links up correctly.
149      * @return A populated and ready-to-use workflow lookupable.Row.
150      */
151     public static org.kuali.rice.kns.web.ui.Row buildTextRow(Class propertyClass, String boPropertyName, String workflowPropertyKey) {
152         if (propertyClass == null) {
153             throw new IllegalArgumentException("Method parameter 'propertyClass' was passed a NULL value.");
154         }
155         if (StringUtils.isBlank(boPropertyName)) {
156             throw new IllegalArgumentException("Method parameter 'boPropertyName' was passed a NULL or blank value.");
157         }
158         if (StringUtils.isBlank(workflowPropertyKey)) {
159             throw new IllegalArgumentException("Method parameter 'workflowPropertyKey' was passed a NULL or blank value.");
160         }
161         List<Field> fields = new ArrayList<Field>();
162         org.kuali.rice.kns.web.ui.Field field;
163         field = FieldUtils.getPropertyField(propertyClass, boPropertyName, false);
164         fields.add(field);
165         return new Row(fields);
166     }
167 
168     /**
169      * This method builds a workflow-lookup-screen Row of type TEXT, with the attached lookup icon and functionality.
170      *
171      * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber.
172      * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for
173      *        Account.accountNumber.
174      * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This
175      *        key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so
176      *        everything links up correctly.
177      * @return A populated and ready-to-use workflow lookupable.Row, which includes both the property field and the lookup icon.
178      */
179     public static org.kuali.rice.kns.web.ui.Row buildTextRowWithLookup(Class propertyClass, String boPropertyName, String workflowPropertyKey) {
180         return buildTextRowWithLookup(propertyClass, boPropertyName, workflowPropertyKey, null);
181     }
182 
183     /**
184      * This method builds a workflow-lookup-screen Row of type TEXT, with the attached lookup icon and functionality.
185      *
186      * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber.
187      * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for
188      *        Account.accountNumber.
189      * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This
190      *        key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so
191      *        everything links up correctly.
192      * @param fieldConversionsByBoPropertyName A list of extra field conversions where the key is the business object property name
193      *        and the value is the workflow property key
194      * @return A populated and ready-to-use workflow lookupable.Row, which includes both the property field and the lookup icon.
195      */
196     public static org.kuali.rice.kns.web.ui.Row buildTextRowWithLookup(Class propertyClass, String boPropertyName, String workflowPropertyKey, Map fieldConversionsByBoPropertyName) {
197         if (propertyClass == null) {
198             throw new IllegalArgumentException("Method parameter 'propertyClass' was passed a NULL value.");
199         }
200         if (StringUtils.isBlank(boPropertyName)) {
201             throw new IllegalArgumentException("Method parameter 'boPropertyName' was passed a NULL or blank value.");
202         }
203         if (StringUtils.isBlank(workflowPropertyKey)) {
204             throw new IllegalArgumentException("Method parameter 'workflowPropertyKey' was passed a NULL or blank value.");
205         }
206         org.kuali.rice.kns.web.ui.Field field;
207         field = FieldUtils.getPropertyField(propertyClass, boPropertyName, false);
208 
209         List<Field> fields = new ArrayList<Field>();
210         fields.add(field);
211         return new Row(fields);
212     }
213 
214     /**
215      * This method builds a workflow-lookup-screen Row of type DROPDOWN.
216      *
217      * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber.
218      * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for
219      *        Account.accountNumber.
220      * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This
221      *        key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so
222      *        everything links up correctly.
223      * @param optionMap The map of value, text pairs that will be used to constuct the dropdown list.
224      * @return A populated and ready-to-use workflow lookupable.Row.
225      */
226     public static org.kuali.rice.kns.web.ui.Row buildDropdownRow(Class propertyClass, String boPropertyName, String workflowPropertyKey, Map<String, String> optionMap, boolean addBlankRow) {
227         if (propertyClass == null) {
228             throw new IllegalArgumentException("Method parameter 'propertyClass' was passed a NULL value.");
229         }
230         if (StringUtils.isBlank(boPropertyName)) {
231             throw new IllegalArgumentException("Method parameter 'boPropertyName' was passed a NULL or blank value.");
232         }
233         if (StringUtils.isBlank(workflowPropertyKey)) {
234             throw new IllegalArgumentException("Method parameter 'workflowPropertyKey' was passed a NULL or blank value.");
235         }
236         if (optionMap == null) {
237             throw new IllegalArgumentException("Method parameter 'optionMap' was passed a NULL value.");
238         }
239         List<Field> fields = new ArrayList<Field>();
240         org.kuali.rice.kns.web.ui.Field field;
241         field = FieldUtils.getPropertyField(propertyClass, boPropertyName, false);
242         fields.add(field);
243         return new Row(fields);
244     }
245 }