001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.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/ecl1.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.workflow;
017:
018: import java.io.BufferedReader;
019: import java.io.StringReader;
020: import java.util.ArrayList;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.Set;
026:
027: import javax.xml.parsers.DocumentBuilderFactory;
028: import javax.xml.xpath.XPath;
029: import javax.xml.xpath.XPathConstants;
030: import javax.xml.xpath.XPathExpressionException;
031:
032: import org.apache.commons.lang.StringUtils;
033: import org.apache.log4j.Logger;
034: import org.kuali.RicePropertyConstants;
035: import org.kuali.core.service.DataDictionaryService;
036: import org.kuali.core.util.FieldUtils;
037: import org.kuali.core.util.KualiDecimal;
038: import org.kuali.core.workflow.WorkflowUtils;
039: import org.kuali.core.workflow.attribute.WorkflowLookupableImpl;
040: import org.kuali.kfs.bo.SourceAccountingLine;
041: import org.kuali.kfs.bo.TargetAccountingLine;
042: import org.kuali.kfs.context.SpringContext;
043: import org.kuali.kfs.document.AccountingDocument;
044: import org.w3c.dom.Document;
045: import org.xml.sax.InputSource;
046:
047: import edu.iu.uis.eden.doctype.DocumentType;
048: import edu.iu.uis.eden.engine.RouteContext;
049: import edu.iu.uis.eden.lookupable.Field;
050: import edu.iu.uis.eden.lookupable.Row;
051:
052: /**
053: * This class contains static utility methods used by the Kuali Workflow Attribute Classes.
054: */
055: public class KualiWorkflowUtils extends WorkflowUtils {
056: private static final Logger LOG = Logger
057: .getLogger(KualiWorkflowUtils.class);
058:
059: /*
060: * the following is so verbose because most times the match anywhere prefix is used and the verboseness prevents bad matching if
061: * a document has an attribute named 'report'
062: */
063: public static final String XPATH_ELEMENT_SEPARATOR = "/";
064: private static final String GENERATED_CONTENT_MAIN_TAG = "generatedContent";
065: private static final String GENERATED_CONTENT_SUB_TAG = "report_for_routing_purposes";
066: public static final String XML_REPORT_DOC_CONTENT_PREFIX = "<"
067: + GENERATED_CONTENT_MAIN_TAG + "><"
068: + GENERATED_CONTENT_SUB_TAG + ">";
069: public static final String XML_REPORT_DOC_CONTENT_SUFFIX = "</"
070: + GENERATED_CONTENT_SUB_TAG + "></"
071: + GENERATED_CONTENT_MAIN_TAG + ">";
072: public static final String XML_REPORT_DOC_CONTENT_XPATH_PREFIX = GENERATED_CONTENT_MAIN_TAG
073: + XPATH_ELEMENT_SEPARATOR + GENERATED_CONTENT_SUB_TAG;
074:
075: // no trailing slash
076: public static final String NEW_MAINTAINABLE_PREFIX_NTS = KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX
077: + "newMaintainableObject/businessObject";
078: public static final String OLD_MAINTAINABLE_PREFIX_NTS = KualiWorkflowUtils.XSTREAM_MATCH_ANYWHERE_PREFIX
079: + "oldMaintainableObject/businessObject";
080: public static final String NEW_MAINTAINABLE_PREFIX = NEW_MAINTAINABLE_PREFIX_NTS
081: + XPATH_ELEMENT_SEPARATOR;
082: public static final String OLD_MAINTAINABLE_PREFIX = KualiWorkflowUtils.OLD_MAINTAINABLE_PREFIX_NTS
083: + XPATH_ELEMENT_SEPARATOR;
084: public static final String ACCOUNT_DOC_TYPE = "AccountMaintenanceDocument";
085: public static final String ACCOUNT_DEL_DOC_TYPE = "DelegateMaintenanceDocument";
086: public static final String ACCOUNT_DELEGATE_GLOBAL_DOC_TYPE = "DelegateGlobal";
087: public static final String ACCOUNT_CHANGE_DOC_TYPE = "AccountGlobalMaintenanceDocument";
088: public static final String SUB_ACCOUNT_DOC_TYPE = "SubAccountMaintenanceDocument";
089: public static final String SUB_OBJECT_DOC_TYPE = "SubObjCdMaintenanceDocument";
090: public static final String OBJECT_CODE_CHANGE_DOC_TYPE = "ObjectCodeGlobalMaintenanceDocument";
091: public static final String INTERNAL_BILLING_DOC_TYPE = "InternalBillingDocument";
092: public static final String PRE_ENCUMBRANCE_DOC_TYPE = "PreEncumbranceDocument";
093: public static final String DISBURSEMENT_VOCHER_DOC_TYPE = "DisbursementVoucherDocument";
094: public static final String NON_CHECK_DISBURSEMENT_DOC_TYPE = "NonCheckDisbursementDocument";
095: public static final String PROCUREMENT_CARD_DOC_TYPE = "ProcurementCardDocument";
096: public static final String BUDGET_ADJUSTMENT_DOC_TYPE = "BudgetAdjustmentDocument";
097: public static final String GENERAL_ERROR_CORRECTION_DOC_TYPE = "GeneralErrorCorrectionDocument";
098: public static final String GENERAL_LEDGER_ERROR_CORRECTION_DOC_TYPE = "CorrectionDocument";
099: public static final String MAINTENANCE_DOC_TYPE = "KualiMaintenanceDocument";
100: public static final String FINANCIAL_DOC_TYPE = "KualiFinancialDocument";
101: public static final String FINANCIAL_YEAR_END_DOC_TYPE = "KualiFinancialYearEndDocument";
102: public static final String FIS_USER_DOC_TYPE = "KualiUserMaintenanceDocument";
103: public static final String ORGANIZATION_DOC_TYPE = "OrgMaintenanceDocument";
104: public static final String PROJECT_CODE_DOC_TYPE = "ProjectCodeMaintenanceDocument";
105: public static final String KRA_BUDGET_DOC_TYPE = "KualiBudgetDocument";
106: public static final String KRA_ROUTING_FORM_DOC_TYPE = "KualiRoutingFormDocument";
107: public static final String SIMPLE_MAINTENANCE_DOC_TYPE = "KualiSimpleMaintenanceDocument";
108: public static final String SUB_OBJECT_CODE_CHANGE_DOC_TYPE = "SubObjCdGlobalMaintenanceDocument";
109: public static final String ORG_REVERSION_CHANGE_DOC_TYPE = "OrganizationReversionGlobalMaintenanceDocument";
110: public static final String C_G_AWARD_DOC_TYPE = "AwardMaintenanceDocument";
111: public static final String C_G_PROPOSAL_DOC_TYPE = "ProposalMaintenanceDocument";
112: public static final String USER_DOC_TYPE = "UniversalUserMaintenanceDocument";
113: public static final String CHART_ORG_WORKGROUP_DOC_TYPE = "ChartOrgWorkgroup";
114: public static final String ACCOUNTS_PAYABLE_CREDIT_MEMO_DOCUMENT_TYPE = "CreditMemoDocument";
115: public static final String ACCOUNTS_PAYABLE_PAYMENT_REQUEST_DOCUMENT_TYPE = "PaymentRequestDocument";
116: public static final String FINANCIAL_DOCUMENT_TOTAL_AMOUNT_XPATH = xstreamSafeXPath(XSTREAM_MATCH_ANYWHERE_PREFIX
117: + RicePropertyConstants.DOCUMENT_HEADER
118: + XPATH_ELEMENT_SEPARATOR
119: + RicePropertyConstants.FINANCIAL_DOCUMENT_TOTAL_AMOUNT
120: + "/value");
121: public static final String ACCOUNT_GLOBAL_DETAILS_XPATH = xstreamSafeXPath(NEW_MAINTAINABLE_PREFIX
122: + "accountGlobalDetails/list/org.kuali.module.chart.bo.AccountGlobalDetail");
123: public static final String ORG_REVERSION_GLOBALS_XPATH = xstreamSafeXPath(NEW_MAINTAINABLE_PREFIX
124: + "organizationReversionGlobalOrganizations/list/org.kuali.module.chart.bo.OrganizationReversionGlobalOrganization");
125:
126: public class RouteLevels {
127:
128: public static final int ADHOC = 0;
129: public static final int EXCEPTION = -1;
130: public static final int ORG_REVIEW = 1;
131:
132: }
133:
134: public class RouteLevelNames {
135:
136: public static final String ACCOUNT_REVIEW = "Account Review";
137: public static final String SUB_ACCOUNT_REVIEW = "Sub Account Review";
138: public static final String ORG_REVIEW = "Org Review";
139: public static final String EMPLOYEE_INDICATOR = "Employee Indicator";
140: public static final String TAX_CONTROL_CODE = "Tax Control Code";
141: public static final String ALIEN_INDICATOR = "Alien Indicator";
142: public static final String PAYMENT_REASON = "Payment Reason";
143: public static final String PAYMENT_REASON_CAMPUS = "Payment Reason+Campus Code";
144: public static final String CAMPUS_CODE = "Campus Code";
145: public static final String ALIEN_INDICATOR_PAYMENT_REASON = "Alien Indicator+Payment Reason";
146: public static final String PAYMENT_METHOD = "Payment Method";
147: public static final String ACCOUNT_REVIEW_FULL_EDIT = "Account Review Full Edit";
148:
149: }
150:
151: public static final Set SOURCE_LINE_ONLY_DOCUMENT_TYPES = new HashSet();
152: static {
153: SOURCE_LINE_ONLY_DOCUMENT_TYPES
154: .add(DISBURSEMENT_VOCHER_DOC_TYPE);
155: }
156:
157: public static final Set TARGET_LINE_ONLY_DOCUMENT_TYPES = new HashSet();
158: static {
159: TARGET_LINE_ONLY_DOCUMENT_TYPES.add(INTERNAL_BILLING_DOC_TYPE);
160: TARGET_LINE_ONLY_DOCUMENT_TYPES.add(PROCUREMENT_CARD_DOC_TYPE);
161: }
162:
163: public static boolean isSourceLineOnly(String documentTypeName) {
164: return SOURCE_LINE_ONLY_DOCUMENT_TYPES
165: .contains(documentTypeName);
166: }
167:
168: public static boolean isTargetLineOnly(String documentTypeName) {
169: return TARGET_LINE_ONLY_DOCUMENT_TYPES
170: .contains(documentTypeName);
171: }
172:
173: public static final boolean isMaintenanceDocument(
174: DocumentType documentType) {
175: LOG.info("started isMaintenanceDocument: "
176: + documentType.getName());
177: boolean isMaintenanceDocument = false;
178: DocumentType currentDocumentType = documentType
179: .getParentDocType();
180: while ((currentDocumentType != null) && !isMaintenanceDocument) {
181: if (MAINTENANCE_DOC_TYPE.equals(currentDocumentType
182: .getName())) {
183: isMaintenanceDocument = true;
184: } else {
185: currentDocumentType = currentDocumentType
186: .getParentDocType();
187: }
188: }
189: LOG.info(new StringBuffer("finished isMaintenanceDocument: ")
190: .append(documentType.getName()).append(" - ").append(
191: isMaintenanceDocument));
192: return isMaintenanceDocument;
193: }
194:
195: /**
196: * TODO: remove this method when we upgrade to workflow 2.2 - the problem that this helps with is as follows:
197: * StandardWorkflowEngine is not currently setting up the DocumentContent on the RouteContext object. Instead that's being
198: * handled by the RequestsNode which, in the case of the BudgetAdjustmentDocument, we never pass through before hitting the
199: * first split. So, in that particular case, we have to reference an attribute that gives us the xml string and translate that
200: * to a dom document ourselves.
201: *
202: * @param xmlDocumentContent
203: * @return a dom representation of the xml provided
204: * @deprecated
205: */
206: public static final Document getDocument(String xmlDocumentContent) {
207: try {
208: return DocumentBuilderFactory
209: .newInstance()
210: .newDocumentBuilder()
211: .parse(
212: new InputSource(
213: new BufferedReader(
214: new StringReader(
215: xmlDocumentContent))));
216: } catch (Exception e) {
217: throw new RuntimeException(
218: KualiWorkflowUtils.class.getName()
219: + " encountered an exception while attempting to convert and xmlDocumentContent String into a org.w3c.dom.Document",
220: e);
221: }
222: }
223:
224: /**
225: * This method uses the document type name to get the AccountingDocument implementation class from the data dictionary, creates
226: * a new instance and uses the getSourceAccountingLine method to get the name of the source accounting line class. It is
227: * intended for use by our workflow attributes when building xpath expressions
228: *
229: * @param documentTypeName the document type name to use when querying the TransactionalDocumentDataDictionaryService
230: * @return the name of the source accounting line class associated with the specified workflow document type name
231: */
232: public static final String getSourceAccountingLineClassName(
233: String documentTypeName) {
234: Class documentClass = SpringContext.getBean(
235: DataDictionaryService.class)
236: .getDocumentClassByTypeName(documentTypeName);
237: if (!AccountingDocument.class.isAssignableFrom(documentClass)) {
238: throw new IllegalArgumentException(
239: "getSourceAccountingLineClassName method of KualiWorkflowUtils requires a documentTypeName String that corresponds to a class that implments AccountingDocument");
240: }
241: try {
242: Class sourceAccountingLineClass = ((AccountingDocument) documentClass
243: .newInstance()).getSourceAccountingLineClass();
244: String sourceAccountingLineClassName = null;
245: if (sourceAccountingLineClass != null) {
246: sourceAccountingLineClassName = sourceAccountingLineClass
247: .getName();
248: } else {
249: sourceAccountingLineClassName = SourceAccountingLine.class
250: .getName();
251: }
252: return sourceAccountingLineClassName;
253: } catch (InstantiationException e) {
254: throw new RuntimeException(
255: "getSourceAccountingLineClassName method of KualiWorkflowUtils caught InstantiationException while try to create instance of class: "
256: + documentClass);
257: } catch (IllegalAccessException e) {
258: throw new RuntimeException(
259: "getSourceAccountingLineClassName method of KualiWorkflowUtils caught IllegalAccessException while try to create instance of class: "
260: + documentClass);
261: }
262: }
263:
264: /**
265: * This method uses the document type name to get the AccountingDocument implementation class from the data dictionary, creates
266: * a new instance and uses the getTargetAccountingLine method to get the name of the target accounting line class. It is
267: * intended for use by our workflow attributes when building xpath expressions
268: *
269: * @param documentTypeName the document type name to use when querying the TransactionalDocumentDataDictionaryService
270: * @return the name of the target accounting line class associated with the specified workflow document type name
271: */
272: public static final String getTargetAccountingLineClassName(
273: String documentTypeName) {
274: Class documentClass = SpringContext.getBean(
275: DataDictionaryService.class)
276: .getDocumentClassByTypeName(documentTypeName);
277: if (!AccountingDocument.class.isAssignableFrom(documentClass)) {
278: throw new IllegalArgumentException(
279: "getTargetAccountingLineClassName method of KualiWorkflowUtils requires a documentTypeName String that corresponds to a class that implments AccountingDocument");
280: }
281: try {
282: Class targetAccountingLineClass = ((AccountingDocument) documentClass
283: .newInstance()).getTargetAccountingLineClass();
284: String targetAccountingLineClassName = null;
285: if (targetAccountingLineClass != null) {
286: targetAccountingLineClassName = targetAccountingLineClass
287: .getName();
288: } else {
289: targetAccountingLineClassName = TargetAccountingLine.class
290: .getName();
291: }
292: return targetAccountingLineClassName;
293: } catch (InstantiationException e) {
294: throw new RuntimeException(
295: "getTargetAccountingLineClassName method of KualiWorkflowUtils caught InstantiationException while try to create instance of class: "
296: + documentClass);
297: } catch (IllegalAccessException e) {
298: throw new RuntimeException(
299: "getTargetAccountingLineClassName method of KualiWorkflowUtils caught IllegalAccessException while try to create instance of class: "
300: + documentClass);
301: }
302: }
303:
304: /**
305: * This method returns a label from the data dictionary service
306: *
307: * @param businessObjectClass - class where the label should come from
308: * @param attributeName - name of the attribute you need the label for
309: * @return the label from the data dictionary for the given Class and attributeName or null if not found
310: */
311: public static final String getBusinessObjectAttributeLabel(
312: Class businessObjectClass, String attributeName) {
313: return SpringContext.getBean(DataDictionaryService.class)
314: .getAttributeLabel(businessObjectClass, attributeName);
315: }
316:
317: /**
318: * This method will do a simple XPath.evaluate, while wrapping your xpathExpression with the xstreamSafe function. It assumes a
319: * String result, and will return such. If an XPathExpressionException is thrown, this will be re-thrown within a
320: * RuntimeException.
321: *
322: * @param xpath A correctly initialized XPath instance.
323: * @param xpathExpression Your XPath Expression that needs to be wrapped in an xstreamSafe wrapper and run.
324: * @param item The document contents you will be searching within.
325: * @return The string value of the xpath.evaluate().
326: */
327: public static final String xstreamSafeEval(XPath xpath,
328: String xpathExpression, Object item) {
329: String xstreamSafeXPath = xstreamSafeXPath(xpathExpression);
330: String evalResult = "";
331: try {
332: evalResult = xpath.evaluate(xstreamSafeXPath, item);
333: } catch (XPathExpressionException e) {
334: throw new RuntimeException(
335: "XPathExpressionException occurred on xpath: "
336: + xstreamSafeXPath, e);
337: }
338: return evalResult;
339: }
340:
341: /**
342: * This method wraps the passed-in XPath expression in XStream Safe wrappers, so that XStream generated reference links will be
343: * handled correctly.
344: *
345: * @param xpathExpression The XPath Expression you wish to use.
346: * @return Your XPath Expression wrapped in the XStreamSafe wrapper.
347: */
348: public static final String xstreamSafeXPath(String xpathExpression) {
349: return new StringBuilder(XSTREAM_SAFE_PREFIX).append(
350: xpathExpression).append(XSTREAM_SAFE_SUFFIX).toString();
351: }
352:
353: /**
354: * This is for use by xml WorkflowAttribute implementations. It overrides the label and help url of the test fields on the
355: * edu.iu.uis.eden.lookupable.Rows obtained from the workflow parent class with the appropriate values from the data dictionary.
356: *
357: * @param workflowRows A list of edu.iu.uis.eden.lookupable.Row objects provided by the workflow superclass, based on the XML
358: * attribute definition.
359: * @param businessObjectClass The BusinessObject Class extracted from the meta data specified in the XML attribute definition,
360: * which is used in querying the data dictionary for the field definition.
361: */
362: public static List setKualiFieldValues(List workflowRows,
363: String businessObjectClassName) {
364: Iterator workflowRowsItr = workflowRows.iterator();
365: while (workflowRowsItr.hasNext()) {
366: edu.iu.uis.eden.lookupable.Row row = (edu.iu.uis.eden.lookupable.Row) workflowRowsItr
367: .next();
368: Iterator fieldItr = row.getFields().iterator();
369: while (fieldItr.hasNext()) {
370: edu.iu.uis.eden.lookupable.Field field = row
371: .getField(0);
372: if (edu.iu.uis.eden.lookupable.Field.TEXT.equals(field
373: .getFieldType())) {
374: try {
375: org.kuali.core.web.ui.Field kualiField = FieldUtils
376: .getPropertyField(
377: Class
378: .forName(businessObjectClassName),
379: field.getPropertyName(), false);
380: field.setFieldLabel(kualiField.getFieldLabel());
381: field.setFieldHelpUrl(KualiWorkflowUtils
382: .getHelpUrl(kualiField));
383: } catch (ClassNotFoundException cnfe) {
384: throw new RuntimeException(
385: "Unable to load BusinessObject class: "
386: + businessObjectClassName, cnfe);
387: }
388: }
389: }
390: }
391: return workflowRows;
392: }
393:
394: /**
395: * This method builds a workflow-lookup-screen Row of type TEXT, with no quickfinder/lookup.
396: *
397: * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber.
398: * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for
399: * Account.accountNumber.
400: * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This
401: * key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so
402: * everything links up correctly.
403: * @return A populated and ready-to-use workflow lookupable.Row.
404: */
405: public static edu.iu.uis.eden.lookupable.Row buildTextRow(
406: Class propertyClass, String boPropertyName,
407: String workflowPropertyKey) {
408: if (propertyClass == null) {
409: throw new IllegalArgumentException(
410: "Method parameter 'propertyClass' was passed a NULL value.");
411: }
412: if (StringUtils.isBlank(boPropertyName)) {
413: throw new IllegalArgumentException(
414: "Method parameter 'boPropertyName' was passed a NULL or blank value.");
415: }
416: if (StringUtils.isBlank(workflowPropertyKey)) {
417: throw new IllegalArgumentException(
418: "Method parameter 'workflowPropertyKey' was passed a NULL or blank value.");
419: }
420: List chartFields = new ArrayList();
421: org.kuali.core.web.ui.Field field;
422: field = FieldUtils.getPropertyField(propertyClass,
423: boPropertyName, false);
424: chartFields
425: .add(new Field(field.getFieldLabel(),
426: KualiWorkflowUtils.getHelpUrl(field),
427: Field.TEXT, false, workflowPropertyKey, field
428: .getPropertyValue(), field
429: .getFieldValidValues(), null,
430: workflowPropertyKey));
431: return new Row(chartFields);
432: }
433:
434: /**
435: * This method builds a workflow-lookup-screen Row of type TEXT, with the attached lookup icon and functionality.
436: *
437: * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber.
438: * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for
439: * Account.accountNumber.
440: * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This
441: * key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so
442: * everything links up correctly.
443: * @return A populated and ready-to-use workflow lookupable.Row, which includes both the property field and the lookup icon.
444: */
445: public static edu.iu.uis.eden.lookupable.Row buildTextRowWithLookup(
446: Class propertyClass, String boPropertyName,
447: String workflowPropertyKey) {
448: return buildTextRowWithLookup(propertyClass, boPropertyName,
449: workflowPropertyKey, null);
450: }
451:
452: /**
453: * This method builds a workflow-lookup-screen Row of type TEXT, with the attached lookup icon and functionality.
454: *
455: * @param propertyClass The Class of the BO that this row is based on. For example, Account.class for accountNumber.
456: * @param boPropertyName The property name on the BO that this row is based on. For example, accountNumber for
457: * Account.accountNumber.
458: * @param workflowPropertyKey The workflow-lookup-screen property key. For example, account_nbr for Account.accountNumber. This
459: * key can be anything, but needs to be consistent with what is used for the row/field key on the java attribute, so
460: * everything links up correctly.
461: * @param fieldConversionsByBoPropertyName A list of extra field conversions where the key is the business object property name
462: * and the value is the workflow property key
463: * @return A populated and ready-to-use workflow lookupable.Row, which includes both the property field and the lookup icon.
464: */
465: public static edu.iu.uis.eden.lookupable.Row buildTextRowWithLookup(
466: Class propertyClass, String boPropertyName,
467: String workflowPropertyKey,
468: Map fieldConversionsByBoPropertyName) {
469: if (propertyClass == null) {
470: throw new IllegalArgumentException(
471: "Method parameter 'propertyClass' was passed a NULL value.");
472: }
473: if (StringUtils.isBlank(boPropertyName)) {
474: throw new IllegalArgumentException(
475: "Method parameter 'boPropertyName' was passed a NULL or blank value.");
476: }
477: if (StringUtils.isBlank(workflowPropertyKey)) {
478: throw new IllegalArgumentException(
479: "Method parameter 'workflowPropertyKey' was passed a NULL or blank value.");
480: }
481: org.kuali.core.web.ui.Field field;
482: field = FieldUtils.getPropertyField(propertyClass,
483: boPropertyName, false);
484:
485: // build the quickFinder/lookupableName info
486: String lookupableClassNameImpl = WorkflowLookupableImpl
487: .getLookupableImplName(propertyClass);
488: StringBuffer fieldConversions = new StringBuffer(
489: WorkflowLookupableImpl.LOOKUPABLE_IMPL_NAME_PREFIX);
490: fieldConversions.append(boPropertyName + ":"
491: + workflowPropertyKey);
492: if (fieldConversionsByBoPropertyName != null) {
493: for (Object entry : fieldConversionsByBoPropertyName
494: .entrySet()) {
495: Map.Entry entryObject = (Map.Entry) entry;
496: fieldConversions
497: .append(",")
498: .append(
499: WorkflowLookupableImpl.LOOKUPABLE_IMPL_NAME_PREFIX)
500: .append(
501: entryObject.getKey() + ":"
502: + entryObject.getValue());
503: }
504: }
505: String lookupableName = WorkflowLookupableImpl
506: .getLookupableName(lookupableClassNameImpl,
507: fieldConversions.toString());
508:
509: List chartFields = new ArrayList();
510: chartFields.add(new Field(field.getFieldLabel(),
511: KualiWorkflowUtils.getHelpUrl(field), Field.TEXT, true,
512: workflowPropertyKey, field.getPropertyValue(), field
513: .getFieldValidValues(),
514: lookupableClassNameImpl, workflowPropertyKey));
515: chartFields.add(new Field("", "", Field.QUICKFINDER, false, "",
516: "", null, lookupableName)); // quickfinder/lookup icon
517: return new Row(chartFields);
518: }
519:
520: /**
521: * This method gets the document total amount from the DocumentHeader If an XPathExpressionException is thrown, this will be
522: * re-thrown within a RuntimeException.
523: *
524: * @param routeContext The RouteContext object from the workflow system
525: * @return the KualiDecimal value of the total amount from the document's workflow document content or null if the amount value
526: * cannot be found.
527: */
528: public static KualiDecimal getFinancialDocumentTotalAmount(
529: RouteContext routeContext) {
530: Document document = routeContext.getDocumentContent()
531: .getDocument();
532: return getFinancialDocumentTotalAmount(document);
533: }
534:
535: /**
536: * This method gets the document total amount from the DocumentHeader <br>
537: * If an XPathExpressionException is thrown, this will be re-thrown within a RuntimeException.
538: *
539: * @param document - the document object from the workflow system
540: * @return the KualiDecimal value of the total amount from the document's workflow document content or null if the amount value
541: * cannot be found.
542: */
543: public static KualiDecimal getFinancialDocumentTotalAmount(
544: Document document) {
545: XPath xpath = getXPath(document);
546: String docTotalAmount = null;
547: String xpathXpression = FINANCIAL_DOCUMENT_TOTAL_AMOUNT_XPATH;
548: try {
549: docTotalAmount = (String) xpath.evaluate(xpathXpression,
550: document, XPathConstants.STRING);
551: if (StringUtils.isEmpty(docTotalAmount)) {
552: String message = "Cannot find financial document total amount";
553: LOG.warn("getDocumentTotalAmount() " + message);
554: return null;
555: }
556: return new KualiDecimal(docTotalAmount);
557: } catch (XPathExpressionException xe) {
558: String errorMsg = "Error executing XPath expression - '"
559: + xpathXpression + "'";
560: LOG.error(errorMsg, xe);
561: throw new RuntimeException(errorMsg, xe);
562: }
563: }
564:
565: }
|