Customizing kuali a technical perspective
Sponsored Links
This presentation is the property of its rightful owner.
1 / 73

Customizing Kuali: A Technical Perspective PowerPoint PPT Presentation


  • 140 Views
  • Uploaded on
  • Presentation posted in: General

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.

Download Presentation

Customizing Kuali: A Technical Perspective

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


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)


Business Rule From Administration Tab


Business Rule Security Example


Business Rule Example


Business Rule Examples


Sample Code Using Business Rule inTaxNumberService

/**

*Splitsthesetoftaxnumberformatswhicharereturned * fromtheruleserviceasasemicolon-delimitedString

* into aStringarray.

*

[email protected]

*/

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.


Payment Request Rule Hierarchy


Business Rule Framework


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 {

/**

[email protected]

[email protected]

*/

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


Create New Payment Request


Checking for Duplication


Showing Other Action Buttons


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;

}


Payment Request Duplication Scenario

  • Needed to check for Payment Request duplication before even validating business rules

  • In case of duplication give the user a warning and the option of override the warning and continue or to cancel

  • We used the question framework for this

  • Demo this in action in Payment Request

  • Demo the code (paymentRequestAction.continuePREQ())


PaymentRequestAction

public ActionForward continuePREQ(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {

PaymentRequestForm preqForm = (PaymentRequestForm) form;

PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) preqForm.getDocument();

Map editMode = preqForm.getEditingMode();

Object question = request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);

PaymentRequestService paymentRequestService = SpringServiceLocator.getPaymentRequestService();

HashMap<String, String> duplicateMessages = paymentRequestService.paymentRequestDuplicateMessages(paymentRequestDocument);


PaymentRequestAction (Continued)

if (!duplicateMessages.isEmpty()){

if (question == null) {

// ask question if not already asked

returnthis.performQuestionWithoutInput(mapping, form, request, response, PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessages.get(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION) , KFSConstants.CONFIRMATION_QUESTION, KFSConstants.ROUTE_METHOD, "");

}

Object buttonClicked = request.getParameter(KFSConstants.QUESTION_CLICKED_BUTTON);

if ((PurapConstants.PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION.equals(question)) && ConfirmationQuestion.NO.equals(buttonClicked)) {

// if no button clicked just reload the doc in the

// INITIATE status and let the user to change the

// input values

paymentRequestDocument.setStatusCode(PurapConstants.PaymentRequestStatuses.INITIATE);

return mapping.findForward(KFSConstants.MAPPING_BASIC);

}

}


Customizing Kuali

Outline:

  • System Parameters

  • Business Rules

  • Authorization class

  • Pre-Rules


Pre-Rules Use Cases

  • Pre-Rules allow

    • Modification of values after form submission (e.g. auto-fill values, possibly based on other values on the form)

    • Switching to another page after clicking the button (e.g. go to a confirmation page)


Pre-Rules Configuration

  • Pre-rules for documents are configured in the data dictionary by specifying a class name for the implementation

  • Example: in UniversalUserMaintenanceDocument.xml

    <preRulesCheckClass>

    org.kuali.core.rules.UniversalUserPreRules

    </preRulesCheckClass>


Pre Rule Checks Architecture


PreRulesCheck Interface

publicinterface PreRulesCheck {

/**

*CallbackmethodfromMaintenanceactionthatallowscheckstobedoneandresponseredirectedviathePreRulesCheckEvent

*

[email protected]

[email protected]

[email protected]

[email protected]

*/

publicboolean processPreRuleChecks(ActionForm form, HttpServletRequest request, PreRulesCheckEvent event);

}


PreRulesContinuationBase

  • This class simplifies requesting clarifying user input prior to applying business rules.

  • It mostly shields the classes that extend it from being aware of the web layer, even though the input is collected via a series of one or more request/response cycles.


PreRulesContinuationBase


PreRulesContinuationBase

publicabstractclass PreRulesContinuationBase implements PreRulesCheck {

protected String question;

protected String buttonClicked;

protected PreRulesCheckEvent event;

protected KualiForm form;

publicabstractboolean doRules(Document document);


PreRulesContinuationBase

publicbooleanprocessPreRuleChecks(ActionForm form, HttpServletRequest request, PreRulesCheckEvent event) {

try {

result = doRules(event.getDocument());

}

catch (IsAskingException e) {

returnfalse;

}

if (isAborting) {

returnfalse;

}

return result;

}


PreRulesCheckEvent


Putting PreRules* in Action

  • Pre-rules are invoked automatically by the framework before routing, approving, and blanket approving a document.

  • Can also force the invocation of a pre-rule by overriding the Struts action handler of the document.


Example 1: Adding a pre-rule check

public class BudgetParametersAction extends BudgetAction {

public ActionForward deletePeriodLine(ActionMapping mapping,

ActionForm form, HttpServletRequest request,

HttpServletResponse response) throws Exception {

// do some processing

ActionForward preRulesForward = preRulesCheck(mapping, form,

request, response);

if (preRulesForward != null) {

return preRulesForward;

}

return mapping.findForward(KFSConstants.MAPPING_BASIC);

}


Example 2: UniversalUserPreRules

publicclass UniversalUserPreRules extends PreRulesContinuationBase {

publicboolean doRules(Document document) {

MaintenanceDocument maintenanceDocument = (MaintenanceDocument) document;

UniversalUser newUser = (UniversalUser) maintenanceDocument.getNewMaintainableObject().getBusinessObject();

Field nameField = FieldUtils.getPropertyField( UniversalUser.class, PropertyConstants.PERSON_NAME, false );

ControlDefinition controlDef = KNSServiceLocator.getDataDictionaryService().getAttributeControlDefinition(UniversalUser.class, PropertyConstants.PERSON_NAME );


Example 2: UniversalUserPreRules (continued)

if ( controlDef.isHidden() || nameField.isReadOnly() || StringUtils.isBlank( newUser.getPersonName() ) ){

if ( !StringUtils.isBlank( newUser.getPersonFirstName() ) && !StringUtils.isBlank( newUser.getPersonLastName() ) ){

if ( !StringUtils.isBlank( newUser.getPersonMiddleName() ) ) {

newUser.setPersonName( newUser.getPersonLastName()+"," +newUser.getPersonFirstName() + " " + newUser.getPersonMiddleName() );

} else {

newUser.setPersonName( newUser.getPersonLastName()+"," +newUser.getPersonFirstName() );

}

}

}

boolean success = true;

List<KualiModule> modules = KNSServiceLocator.getKualiModuleService().getInstalledModules();

PreRulesContinuationBase rule = null;

for ( KualiModule module : modules ) {

rule = (PreRulesContinuationBase) module.getModuleUserPreRules();

if ( rule != null ) {

success &= rule.doRules( document );

}

}


Pre-Rule Scenario Sample 3

  • Pre-Rules could be used to derive values based on other values, or

  • Setting a default value where needed and the user didn’t enter any value

    • See next sample code


Example 3: Set Unconditional Defaults

publicclass DelegateChangePreRules implements PreRulesCheck {

...

privatevoid setUnconditionalDefaults(DelegateChangeContainer newDelegateChangeContainer) {

for (DelegateChangeDocument newDelegateChange : newDelegateChangeContainer.getDelegateChanges()) {

// FROM amount defaults to zero

if (newDelegateChange.getApprovalFromThisAmount()==null) {

newDelegateChange.setApprovalFromThisAmount(new KualiDecimal(0));

}

// TO amount defaults to zero

if (newDelegateChange.getApprovalToThisAmount()==null) {

newDelegateChange.setApprovalToThisAmount(new KualiDecimal(0));

}

}

}


Summary

  • System parameters

    • Provides on-the-fly configuration of certain components

  • Business Rules

    • Provides business rules based on matching values


Summary

  • “Pluggable” business rules

    • Java-based implementation of rules that are more complicated than simple matching

  • Pre-rules

    • Allows modification of form values prior to processing

    • Allows “redirection” to a different page


Questions?

[email protected]


References

  • System parameters/ business rules

    https://test.kuali.org/confluence/x/-kw

  • Pluggable business rules

    https://test.kuali.org/confluence/x/5l

  • Pre-rules

    https://test.kuali.org/confluence/x/WFE

  • Kuali Nervous System (KNS)

    https://test.kuali.org/confluence/x/EU8


  • Login