730 likes | 936 Views
Customizing Kuali: A Technical Perspective. Naser Alavi (Michigan State University) Warren Liang (University of California, Irvine). Customizing Kuali. Outline: System Parameters Business Rules Authorization class Pre-Rules. Customizing Kuali.
E N D
Customizing Kuali:A Technical Perspective Naser Alavi (Michigan State University) Warren Liang (University of California, Irvine)
Customizing Kuali Outline: • System Parameters • Business Rules • Authorization class • Pre-Rules
Customizing Kuali • Which aspects of Kuali are we customizing in this presentation? • Customizing business rules • Customizing authorization • Customizing system parameters
System Parameters/Rules Purpose: • Externalizing constants out of code • They may be maintained by a non-developer via a maintenance document. • The code must be programmed to access the constant value(s) by its unique key.
System Parameters Use Cases Where they may be used: • Business rule checks • Any place where runtime changes to values displayed within the application will be needed without a restart of the application server
System Parameters The System Parameters can be used in the following manners: • Key-value constants • (key=DEBIT, value=D) • Key-value group constants • (key=VALID_OBJECT_CODES_FOR_XYZ, value=5000;5001;3400;2300)
System Parameters Use Cases Where they may not / should not be used: • System configuration values that can’t be represented as constants/literals in the code • Core constants that will not change no matter what the installation • Spring XML configuration files - you cannot have XML files use this mechanism • OJB XML configuration or descriptor files - you cannot have XML files use this mechanism
System Parameters Table • A single parameter record has a composite key made up of: • Parameter Name • Parameter Security Grouping • This composite key helps to categorize our constants. • As an enhancement for next phase to further modularize these parameters a new “Module Code” field will be added to this table
Using System Parameters • Using the System Parameters for Key-Value Constants: String MANDATORY_TRANSFER = kualiConfigurationService .getApplicationParameter("TransactionProcessingEDocs", "Chart.SubObjectCode.MandatoryTransfer"); if (financialSubObjectCode.equals(MANDATORY_TRANSFER)) { ...
Using System Parameters • Using the System Parameters for Key-Value Lists of Constants (array of values) String[] VALID_OBJ_SUB_TYPES_FOR_TOF = SpringServiceLocator.getKualiConfigurationService() .getApplicationParameters("TransactionProcessing", "ValidObjectSubTypeCodesForTofAccountingLines"); if(ArrayUtils.contains(VALID_OBJ_SUB_TYPES_FOR_TOF, accountingLine.getFinancialSubObjectCode())) { ...
System Parameter Security Class/Table • The following class represents a security grouping which is identified by its security group name. • Each security grouping has a workgroup associated with it for authorization purposes.
System Parameter Security Class/Table publicclass FinancialSystemParameterSecurity extends PersistableBusinessObjectBase { … // script name is the security group private String financialSystemScriptName; private String workgroupName; private String financialSystemScriptDescription; private List financialSystemParameters; …
System Parameter Attributes • The following class represents a KFS parameter with an associated text value. • This text value can be interpreted as a single value or a semicolon delimited list of values • The parameter name and the security group name make up the primary key for this business object • The security group name is the link to the System Parameter Security Table
System Parameter Attributes publicclass FinancialSystemParameter extends PersistableBusinessObjectBase { … private String financialSystemScriptName; private String financialSystemParameterName; private String financialSystemParameterText; private String financialSystemParameterDescription; privatebooleanfinancialSystemMultipleValueIndicator; private FinancialSystemParameterSecurity financialSystemParameterSecurity; …
Business Rules • Maintained by Business Rules Tables • Allows Functional Users to maintain and create business rules (to some extent). • Allows institutions to customize out of the box business rules based on their codes and policies.
Business Rules • Uses KualiParameterRule object for evaluating business rules • This object holds the underlying rule record values and provides a conveniencemethod for the evaluation of the rule • You can retrieve the values of a rule record as a KualiParameterRule by using the KualiConfigurationService method: KualiParameterRule getApplicationParameterRule(String scriptName, String parameter)
Sample Code Using Business Rule inTaxNumberService /** *Splitsthesetoftaxnumberformatswhicharereturned * fromtheruleserviceasasemicolon-delimitedString * into aStringarray. * *@returnAStringarrayofthetaxnumberformatregularexpressions. */ public String[] parseSSNFormats() { if(taxNumberFormats == null) { taxNumberFormats = SpringServiceLocator.getKualiConfigurationService().getApplicationRule("PurapAdminGroup","PURAP.TAX_NUMBER_FORMATS"); } String taxFormats = taxNumberFormats.getRuleText(); return taxFormats.split(";"); }
Sample Code Using Business Rule inTaxNumberService publicboolean isValidTaxNumber( String taxNbr, String taxType ) { String[] ssnFormats = parseSSNFormats(); String[] feinFormats = parseFEINFormats(); Integer defaultTaxNbrDigits = new Integer (SpringServiceLocator .getKualiConfigurationService() .getApplicationParameterValue("PurapAdminGroup", "PURAP.DEFAULT_TAX_NUM_DIGITS")); if (taxNbr.length() != defaultTaxNbrDigits || !isStringAllNumbers(taxNbr)) { returnfalse; }
Business Rule Attributes package org.kuali.core.bo; publicclass BusinessRule extends PersistableBusinessObjectBase { private String ruleGroupName; private String ruleName; private String ruleText; private String ruleDescription; private String ruleOperatorCode; privatebooleanfinancialSystemMultipleValueIndicator; privatebooleanfinancialSystemParameterActiveIndicator; BusinessRuleSecurity ruleGroup;
System Parameters/Rules Summary: • Create and populate workgroup that should have maintenance permission • Create corresponding security group • Create parameter (value to control runtime system behavior) or rule (definition of legal/illegal values)
Customizing Kuali Outline: • System Parameters • Business Rules • Authorization class • Pre-Rules
Putting It All Together • Defining a Transactional Document • Payment Request Doc DD XML • Payment Request Rule • Payment Request Authorizer • Payment Request Pre-Rule (using question framework) • Demo New Payment Request Document functionality and sample code
Plugging Business Rules Class • “Pluggable” business rules • Specify business rule implementation in document’s data dictionary file • Registering your business rule class with a document type. • The fully qualified classname of the business rule class must be specified with the <businessRuleClass> tag in the document's data dictionary file.
Plugging Business Rules Class Example, KualiPaymentRequestDocument.xml: <documentClass> org.kuali.module.purap.document.PaymentRequestDocument </documentClass> <businessRulesClass> org.kuali.module.purap.rules.PaymentRequestDocumentRule </businessRulesClass>
Plugging Business Rules Class • “Pluggable” business rules • Normally used to detect errors on a form • Since these are written in Java, it is much more expressive than just matching • Has access to all Kuali services • The rules framework creates a copy of the document so that any changes made during rule application will not affect the document when it is persisted.
DocumentRuleBase • DocumentRuleBase implements common checks that should be run after every event, and rule implementations should extend this class • Instead of overriding the methods defined by the *DocumentRule interfaces, override the processCustom* methods defined in this class (e.g. to define new save rules, override processCustomSaveDocumentBusinessRules instead of processSaveDocument)
Associating Rules with Events(Save Example) package org.kuali.core.rule; /** *Definesarulewhichgetsinvokedimmediatelybeforeadocumentgetssaved. */ publicinterface SaveDocumentRule extends BusinessRule { /** *@paramdocument *@returnfalseiftherulefails */ publicboolean processSaveDocument(Document document); }
Associating Rules with Events and Using Common Services /** *Thisclasscontainsallofthebusinessrulesthatarecommontoalldocuments. */ publicabstractclass DocumentRuleBase implements SaveDocumentRule, RouteDocumentRule, ApproveDocumentRule, AddNoteRule, AddAdHocRoutePersonRule, AdHocRouteWorkgroupRule { privatestatic UniversalUserService universalUserService; privatestatic KualiModuleService kualiModuleService; privatestatic DictionaryValidationService dictionaryValidationService; privatestatic KualiWorkflowInfo workflowInfoService; privatestatic KualiConfigurationService kualiConfigurationService;
DocumentRuleBase Rule Implementation publicabstractclassDocumentRuleBaseimplements SaveDocumentRule, … { publicboolean processSaveDocument(Document document) { boolean isValid = true; isValid &= isDocumentOverviewValid(document); if (isValid) { isValid &= processCustomSaveDocumentBusinessRules(document); } return isValid; } protectedboolean processCustomSaveDocumentBusinessRules (Document document) { returntrue; } }
DocumentRule Sample publicclass PaymentRequestDocumentRule extends AccountsPayableDocumentRuleBase { @Override protectedboolean processCustomSaveDocumentBusinessRules (Document document) { PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) document; return processValidation(paymentRequestDocument); }
DocumentRule Sample publicclass PaymentRequestDocumentRule extends AccountsPayableDocumentRuleBase { …. @Override publicboolean processValidation(PurchasingAccountsPayableDocument purapDocument) { boolean valid = super.processValidation(purapDocument); valid &= processInvoiceValidation((PaymentRequestDocument)purapDocument); valid &= processPurchaseOrderIDValidation((PaymentRequestDocument)purapDocument); valid &= processPaymentRequestDateValidation((PaymentRequestDocument)purapDocument); return valid; }
Customizing Kuali Outline: • System Parameters • Business Rules • Authorization class • Pre-Rules
Plugging Authorizer Class • Modifying Authorizations for a Document Type • Payment Request Document • Initiators in Doc DD XML • Complex Rules in Document Authorizer Class • Approvals in Workflow
Plugging Authorizer Class Authorization DD File Code Sample: <documentClass> org.kuali.module.purap.document.PaymentRequestDocument </documentClass> <documentAuthorizerClass> org.kuali.module.purap.document.PaymentRequestDocumentAuthorizer </documentAuthorizerClass> <authorizations> <authorization action="initiate"> <workgroups> <workgroup>kualiUniversalGroup</workgroup> </workgroups> </authorization> </authorizations> <documentTypeName>KualiPaymentRequestDocument</documentTypeName> <documentTypeCode>PREQ</documentTypeCode>
Document Authorizer • The document authorizer framework: • Determines a user can initiate a document • How document fields are rendered • What buttons are displayed
Code Modules for PaymentRequest The functionality demoed was accomplished through codes in: • PaymentRequestDocumentAuthorizer • PaymentRequestDocumentRule (already discussed) • PaymentRequestAction
PaymentRequestDocumentAuthorizer Overrode these methods: • hasInitiateAuthorization • Simple true/false value • getEditMode • A map of mode -> value mappings. The JSP layer uses these mappings to determine how it should render the document • getDocumentActionFlags • Returns an object with numerous boolean flags, indicating whether a button may be rendered
PaymentRequestDocumentAuthorizer @Override publicboolean hasInitiateAuthorization(Document document, UniversalUser user) { String authorizedWorkgroup = SpringServiceLocator.getKualiConfigurationService().getApplicationParameterValue(PurapRuleConstants.PURAP_ADMIN_GROUP, PurapRuleConstants.PURAP_DOCUMENT_PO_ACTIONS); try { return SpringServiceLocator.getKualiGroupService().getByGroupName(authorizedWorkgroup).hasMember(user); } catch (GroupNotFoundException e) { thrownew RuntimeException("Workgroup " + authorizedWorkgroup + " not found",e); } }
PaymentRequestDocumentAuthorizer @Override public Map getEditMode(Document document, UniversalUser user, List sourceAccountingLines, List targetAccountingLines) { Map editModeMap = super.getEditMode(document, user, sourceAccountingLines, targetAccountingLines); PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument)document; if (StringUtils.equals(paymentRequestDocument.getStatusCode(),PurapConstants.PaymentRequestStatuses.INITIATE)){ editModeMap.put(PurapAuthorizationConstants.PaymentRequestEditMode.DISPLAY_INIT_TAB, "TRUE"); } else { editModeMap.put(PurapAuthorizationConstants.PaymentRequestEditMode.DISPLAY_INIT_TAB, "FALSE"); } return editModeMap; }
PaymentRequestDocumentAuthorizer The JSP uses the values in the edit mode map to determine how to render the document. Example from PaymentRequest.jsp <c:if test="${not KualiForm.editingMode['displayInitTab']}" > <kul:documentOverview editingMode="${KualiForm.editingMode}" includePostingYear="true“ /> </c:if> <c:if test="${KualiForm.editingMode['displayInitTab']}" > <purap:paymentRequestInit documentAttributes="${DataDictionary.KualiPaymentRequestDocument.attributes}“ /> </c:if>
PaymentRequestDocumentAuthorizer @Override public DocumentActionFlags getDocumentActionFlags(Document document, UniversalUser user) { DocumentActionFlags flags = super.getDocumentActionFlags(document, user); KualiWorkflowDocument workflowDocument = document.getDocumentHeader().getWorkflowDocument(); PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument)document; if (StringUtils.equals(paymentRequestDocument .getStatusCode(), INITIATE)){ flags.setCanSave(false); flags.setCanClose(false); flags.setCanCancel(true); } else { flags.setCanSave(true); } return flags; }