Upload
felix-dawson
View
223
Download
0
Embed Size (px)
Citation preview
Installing, Configuring & Customizing KFS
Ailish Byrne (Indiana University)
Naser Alavi (Michigan State University)
Oracle 10.1+
MySQL 5.0+
Data Access Tools
??
Data Access Objects
Object Relational
Bridge
JDBCDatabase Platform
Implementation
p6spy & log4j
Service Tier Tools
Data Access Objects
log4j
ServicesBusiness
Rules
Transaction
Data Dictionary
Workflow
POJOs
POJOs
JSP
Web Client Tools
Serviceslog4j
Dispatch Actions
Request ProcessorForms
Forms
POJOs
POJOs
HTML
Batch Tools
Scheduler Service
log4j
Job Listener
JobStep 1
Step 2Step 3
JDBC Jobstore
Scheduler
Other Tools
Development & Testing
• IDE, e.g. Eclipse 3.2+• KFS test framework
based on Junit 3.8.1• Continuous Integration,
e.g. Anthill Pro 2.50+
Production
• Application Server, e.g. Tomcat 5.5.16+
• Web Server, e.g. Apache 2.0.55+
• Load Balancer, Zeus ZXTM-lb
Evaluation: Database Setup
• Install appropriate version of a supported database
• Install JDBC drivers
• Configure database import/export tool via impex-build.properties
• Perform initial setup steps
• Run bootstrap target
• Import demo data set
Import Flow
Evaluation: Environment Setup
• Configure build process via kuali-build.properties
• Set up java, ant, tomcat, and optionally Eclipse
• Run dist-local (+ make-source, if no IDE)
• Start tomcat
Build Files
• User properties
• Institution shared properties
• Project build.properties
• build.xml
• build directory– external– project
Dist Flow
build/externalSource Destination
appserver/*.jar ${appserver.lib.dir}
appserver/carol.properties ${appserver.classes.dir}
appserver/context.xml ${appserver.localhost.dir} or META-INF directory in war
work/* ${external.work.directory}
log4j.properties ${settings.directory}
security.properties ${security.directory}
build/projectSource Destination
configuration.properties ${source.directory}
spy.properties ${source.directory}
web.xml ${webinf.directory}
help.zip ${help.directory}
rice-<version #>-licenses.zip
${licenses.directory}/rice
rice-<version #>-web.zip ${webroot.directory}
Test Flow
Funcnical Implementation Questions
? Should we use workflow for other applications
? Will our security office frown on the encryption strategy
? How will we source institutional user data
? How and when will our batch schedule run
? Should our static content be release independent and who will maintain it
Configuration & Customization: build.properties
• Deployment• Database platform• Batch• User Maintenance• Authentication• Spring Files• User Interface• User Messages
Configuration & Customization: Spring: Bean Overrides
• User Service
• Authentication Service
• Mail Service
• Encryption Service
• Modules
Configuration & Customization: web.xml
• Workflow
• CAS
• Filters
• Listeners
Configuration & Customization: Spring: Module Definition
• Users
• Authorization
• Data Dictionary
• Database
• Batch
• Javascript
Configuration & Customization: Data Dictionary
• Labels• Presence & Order of Fields• Custom Fields• Inquiry Association• Authorization• Maintainables• Business Rules• Authorization
Functional Implementation Questions
? What will our chart and organization hierarchy look like
? Will we use flexible offsets
? Do we have additional attributes that we need to represent in KFS
? How can we change workflow to meet our approval process
Configuration & Customization: Extended Attributes
• Module Spring bean override
• Database object(s)
• Extension class descriptor & base descriptor override
• Extension business object & rule override
• Extension BO DD entry, base BO and document DD override
• Optional control values & AJAX
Configuration & Customization: Workflow
• Document Types– Exception, blanket approval, etc. workgroups– Route nodes / path– Search configuration
• Rules / Searching– Add templates / modify existing templates– Modify / add XML attribute definitions– Extend and customize java attributes
Configuration & Customization: Parameters
• Configuration– Exception mailing lists– Authorized groups– Derivations
• Validation: simple and compound constraints
• Relative help URLs
Implementation
• Database Setup– Import bootstrap data set– Review data setup page for delivered data description
and dependency information– Determine what you will load through UI vs other– Use the post-data load encryption process as needed
for data not loaded through UI
• Environment Setup– Revisit build properties– Wrap or replace KFS build
Maintaining Customizations
• Additions should reside outside the org.kuali package• Do not modify delivering files (data dictionary, OJB,
spring) – override them• When you need to modify delivered files, use the
keyword: INSTITUTIONAL CUSTOMIZATION (in comment appropriate for file type)
• Track modifications to delivered document types, parameters, workgroups
• Version control or other comparison tool to assist with merge of modifications to delivered files
Upgrade Process
• Get distribution, point at your prior version, run delivered code upgrade process
• Use delivered process to generate database upgrade script, review & execute
• Branch your current development version, replace custom code with the distribution
• Sync and reapply changes
Customizing Kuali
Outline:
• System Parameters
• Business Rules
• Authorization
• Pre-Rules
System Parameters
• Allow institutions to customize out of the box business rules based on their own policies
• Controlled by functional users via maintenance documents
• Externalize constants out of the code • Maintained in System Parameters Tables• Convenient service and evaluator methods are
provided for developers to access and use the constant values in business rules validations
System Parameters Use Cases
• May be used in:– Business rules checks– Runtime changes to values displayed within the
application without a restart of the application server
• May not be used in:– System configuration values that can’t be represented
as constants/literals in the code– Core constants that will not change– Spring XML configuration files– OJB XML descriptor files
System Parameter Tables
• Parameter (SH_Param_T)
• Parameter Namespace (SH_Param_NMSPC_T)
• Parameter Type (SH_PARM_TYP_T)
• Parameter Detailed Type (SH_PARM_DTL_TYP_T)
System Parameter Tables
SH_PARM_NMSPC_T
PK SH_PARM_NMSPC_CD
OBJ_ID VER_NBR SH_PARM_NMSPC_NM ACTIVE_IND
SH_PARM_T
PK,FK1,FK3 SH_PARM_NMSPC_CDPK,FK3 SH_PARM_DTL_TYP_CDPK SH_PARM_NM
OBJ_ID VER_NBRFK2 SH_PARM_TYP_CD SH_PARM_TXT SH_PARM_DESC SH_PARM_CONS_CD WRKGRP_NM
SH_PARM_TYP_T
PK SH_PARM_TYP_CD
OBJ_ID VER_NBR SH_PARM_TYP_NM ACTIVE_IND
SH_PARM_DTL_TYP_T
PK,FK1 SH_PARM_NMSPC_CDPK SH_PARM_DTL_TYP_CD
OBJ_ID VER_NBR SH_PARM_DTL_TYP_NM ACTIVE_IND
Parameter Namespace Table (SH_PARM_NMSPC_T)
High-level classification that allows the association of parameters with a particular application and module• Namespace Code (primary key)
– Format is Application-Module, • KFS-FP (KFS Financial Processing), • KR-NS (Rice Nervous System), • KFS-SY (KFS System Wide)
• Namespace Name • Active Indicator
Parameter Type (SH_PARM_TYP_T)
High-Level classification that allows the groupingof parameters by functional type• Type Code (primary key) • Type Name
– CONFG (Configuration) – VALID (Document Validation)– AUTH (Authorization)– HELP (Help)
• Active Indicator
Parameter Detailed Type Table (SH_PARM_DTL_TYP_T)
Entities or Components such as:– Maintenance tables – Transactional documents – Batch steps
• Namespace Code (primary key) • Detailed Type Code (primary key) • Detailed Type Name • Active Indicator
Parameter Table (SH_PARM_T)
• A single record has a composite key made up of:– Namespace Code (Module Code)
• A group used to organize various parameter records into logical functional units.
– KFS-PA, KFS-GL
– Detailed Type Code (Component)• Entities such as maintenance tables or transactional
documents and batch steps – PaymentRequest, ExtractPdpStep
– Name • The name identifying the parameter
– ACCOUNTS_PAYABLE_GROUP
Parameter Table (SH_PARM_T)
• Namespace Code (primary key) • Detailed Type Code (primary key) • Name (primary key) • Type Code • Workgroup • Value • Description • Constraint (values allowed or disallowed)- must
be A or D
Parameter Business Object
public class Parameter extends PersistableBusinessObjectBase { …private String parameterNamespaceCode;private String parameterDetailTypeCode;private String parameterName;private String parameterValue;private String parameterDescription;private String parameterTypeCode;private String parameterConstraintCode;private String parameterWorkgroupName;private ParameterNamespace parameterNamespace;private ParameterType parameterType;private ParameterDetailType parameterDetailType;…
Accessing System Parameters
System Parameters Lookup
Parameters Module Codes
Parameters Type Codes
Parameters Lookup Example
Parameter Example
Parameter Example
Parameter Example
Parameters Maintenance
• Only KUALI_PARAMETER_MAINTAINERS workgroup members can initiate:– Parameter namespace– Parameter Type– Parameter Detailed Type– Parameter
• Members of a workgroup are authorized to maintain parameters associated with that workgroup. – Changes to any other Parameter field except the value and
operation will be routed to KUALI_PARAMETER_MAINTAINERS
Parameter Developer Use
• Use the methods in the ParameterService to retrieve information about system parameters, value(s), or ParameterEvaluators.
• See the javadoc for– ParameterService/Impl– ParameterEvaluator/Impl– AlwaysSucceedParameterEvaluator/Impl.
ParameterService
• public boolean parameterExists(Class componentClass, String parameterName);
• public String getParameterValue(Class componentClass, String parameterName);
• public String getParameterValue(Class componentClass, String parameterName, String constrainingValue);
• public List<String> getParameterValues(Class componentClass, String parameterName);
• public List<String> getParameterValues(Class componentClass, String parameterName, String constrainingValue);
• public ParameterEvaluator getParameterEvaluator(Class componentClass, String parameterName);
ParameterEvaluator
/** * This is a statefull wrapper for Parameters, which
provides convenient methods to evaluate a constrained value against a Parameter.
*/
public boolean evaluationSucceeds();public boolean constraintIsAllow();public boolean evaluateAndAddError(Class businessObjectOrDocumentClass, String constrainedPropertyName);
Using System Parameter inTaxNumberService
public boolean isValidTaxNumber(String taxNbr, String taxType) {
… Integer defaultTaxNumberDigits =
new Integer(parameterService. getParameterValue(VendorDetail.class, "DEFAULT_TAX_NUMBER_DIGITS"));
if (taxNbr.length() != defaultTaxNumberDigits || !isStringAllNumbers(taxNbr)) {
return false; }…}
Using System Parameters inTaxNumberService
/** * Splits the set of tax number formats which are returned * from the rule service as a semicolon-delimited String * into a String array. * * @return A String array of the tax number format regular * expressions. */ public String[] parseSSNFormats() { if (ObjectUtils.isNull(taxNumberFormats)) { taxNumberFormats =
parameterService.getParameterValues(VendorDetail.class, "TAX_SSN_NUMBER_FORMATS");
} return taxNumberFormats.toArray(new String[] {}); }
System Parameters
Summary:
• Create and populate workgroup that should have maintenance permission
• Create parameter to control runtime system behavior or to define legal/illegal values
Customizing Kuali
Outline:
• System Parameters
• Business Rules
• Authorization
• Pre-Rules
Customizing Payment Request Document Case Study
• Check for duplicated Payment Requests before validating business rules– In case of duplication give the user a warning
and the option for continue or cancel
• Check the pay date before routing
• Customize the rendering of the tabs and buttons on the page based on the document status
Customizing Payment Request Document Case Study
The functionality was provided through customizing codes in:• Payment Request Doc DD XML• Payment Request Rule• Payment Request Authorizer• Payment Request Pre-Rule (using
question framework)• Payment Request Action
Payment Request Document
Payment Request Document
Payment Request Document
Pluggable Business Rules Class
• Pluggable through DD
• Since written in Java, they are much more expressive than just matching
• Has access to all Kuali services
• Extensive code reuse through inheritance and services
Business Rule Framework
Document RuleEvent W Interface
Request
Call rule interface method
Generate event
KualiRuleService
Busines Rule ImplImplemnts rule interface?
Get business rule impl
Return errors
Document.xml
Plugging Business Rules Class
• Register your business rule class with a document type.
• Specify the fully qualified class name of the business rule class with the <businessRuleClass> tag in the document's data dictionary file.
Plugging Business Rules Class
Example, PaymentRequestDocument.xml:
<documentClass>org.kuali.module.purap.document.PaymentRequestDocument
</documentClass>
<businessRulesClass>org.kuali.module.purap.rules.PaymentRequestDocumentRule
</businessRulesClass>
Rule Hierarchy Example
DocumentRuleBase
• Implements common checks that should be run after every event
• Rule implementations should extend this class• Override the
processCustom<event>DocumentBusinessRule() methods defined in this class. Examples: – To define new save rules, override
processCustomSaveDocumentBusinessRules()– To define new route rules, override
processCustomRouteDocumentBusinessRules()
Associating Rules with Events and Using Common Services
/** * This class contains all of the business rules that are
common to all documents. */public abstract class DocumentRuleBase implements
SaveDocumentRule, RouteDocumentRule, ApproveDocumentRule, AddNoteRule, AddAdHocRoutePersonRule, AdHocRouteWorkgroupRule {private static UniversalUserService universalUserService;
private static KualiModuleService kualiModuleService; private static DictionaryValidationService
dictionaryValidationService; private static KualiWorkflowInfo workflowInfoService; private static KualiConfigurationService
kualiConfigurationService;
Associating Rules with Events(Save Example)
package org.kuali.core.rule;
/** * Defines a rule which gets invoked immediately
before a document gets saved. */public interface SaveDocumentRule extends
BusinessRule { /** * @param document * @return false if the rule fails */ public boolean processSaveDocument(Document
document);}
DocumentRuleBase Rule Implementation
public abstract class DocumentRuleBase implements SaveDocumentRule, … {
public boolean processSaveDocument(Document document) { boolean isValid = true; isValid &= isDocumentOverviewValid(document); if (isValid) { isValid &=
processCustomSaveDocumentBusinessRules(document); } return isValid; } protected boolean
processCustomSaveDocumentBusinessRules (Document document) { return true; }}
DocumentRuleBase Rule Implementation
public abstract class DocumentRuleBase implements RouteDocumentRule, … {
public boolean processRouteDocument(Document document) {
boolean isValid = true;isValid &= isDocumentAttributesValid(document,
true); if (isValid) { isValid &=
processCustomRouteDocumentBusinessRules(document); } return isValid; } protected boolean
processCustomRouteDocumentBusinessRules (Document document) { return true; }}
DocumentRule Example
public class PaymentRequestDocumentRule extends AccountsPayableDocumentRuleBase {
@Override protected boolean processCustomSaveDocumentBusinessRules (Document document) { PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) document; return processValidation(paymentRequestDocument); }
DocumentRule Example
public class PaymentRequestDocumentRule extends AccountsPayableDocumentRuleBase {
@Override protected boolean processCustomRouteDocumentBusinessRules(Document document) { boolean isValid = true; PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) document; isValid &= validateRouteFiscal(paymentRequestDocument); isValid &= processValidation(paymentRequestDocument); isValid &= checkNegativeAccounts(paymentRequestDocument); return isValid; }
DocumentRule Example
public class PaymentRequestDocumentRule extends AccountsPayableDocumentRuleBase {
….@Override public boolean
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
• Pre-Rules
Document Authorizer Framework
• Determines who can initiate a document– Initiators in Doc DD XML
• How document fields are rendered
• What buttons are displayed
• Complex Rules in Document Authorizer Class
• Approvals in Workflow
Plugging Authorizer Class
<documentClass>
org.kuali.module.purap.document.PaymentRequestDocument
</documentClass><documentAuthorizerClass>
org.kuali.module.purap.document.PaymentRequestDocumentAuthorizer
</documentAuthorizerClass> <authorizations> <authorization action="initiate"> <workgroups>
<workgroup>KUALI_PURAP_ACCOUNTS_PAYABLE</workgroup> </workgroups> </authorization></authorizations><documentTypeName>KualiPaymentRequestDocument</
documentTypeName><documentTypeCode>PREQ</documentTypeCode>
PaymentRequestDocumentAuthorizer
• Override hasInitiateAuthorization– Simple true/false value
• Override getEditMode– A map of mode -> value mappings. The JSP
layer uses these mappings to determine how it should render the document
• Override getDocumentActionFlags– Returns an object with numerous boolean flags,
indicating whether a button may be rendered
PaymentRequestDocumentAuthorizer
@Override public boolean hasInitiateAuthorization(Document document,
UniversalUser user) { String authorizedWorkgroup =
SpringContext.getBean(ParameterService.class).getParameterValue(ParameterConstants.PURCHASING_DOCUMENT.class, PurapParameterConstants.Workgroups.WORKGROUP_ACCOUNTS_PAYABLE); try {
return SpringContext.getBean(KualiGroupService.class).getByGroupName(authorizedWorkgroup).hasMember(user);
} catch (GroupNotFoundException e) { throw new 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;
}
PaymentRequestAction (Continued)
public ActionForward continuePREQ(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {PaymentRequestForm preqForm = (PaymentRequestForm) form;
PaymentRequestDocument paymentRequestDocument = (PaymentRequestDocument) preqForm.getDocument();
//preform duplicate check which will forward to a //question prompt if one is found
ActionForward forward = performDuplicatePaymentRequestCheck(mapping, form, request, response, paymentRequestDocument);
if (forward != null) { return forward; } ….}
PaymentRequestAction (Continued)
private ActionForward performDuplicatePaymentRequestCheck(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response, PaymentRequestDocument paymentRequestDocument) throws Exception {
ActionForward forward = null; HashMap<String, String> duplicateMessages =
SpringContext.getBean(PaymentRequestService.class).paymentRequestDuplicateMessages(paymentRequestDocument);
// ask question if not already asked if (!duplicateMessages.isEmpty()) { Object question
=request.getParameter(KFSConstants.QUESTION_INST_ATTRIBUTE_NAME);
if (question == null) { return this.performQuestionWithoutInput(mapping,
form, request, response, PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION, duplicateMessages.get(PREQDocumentsStrings.DUPLICATE_INVOICE_QUESTION), KFSConstants.CONFIRMATION_QUESTION, KFSConstants.ROUTE_METHOD, ""); }
PaymentRequestAction (Continued)
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);
forward = mapping.findForward(KFSConstants.MAPPING_BASIC); } }
return forward;}
Customizing Kuali
Outline:
• System Parameters
• Business Rules
• Authorization
• Pre-Rules
Pre-Rules
• Pre-rules are invoked automatically by the framework before saving, routing, approving, and blanket approving a document.
Pre-Rules Use Cases
• Modification of values on the form– Auto-fill values– Setting default values– Deriving values based on other values
• Switching to another page– e.g. go to a confirmation page
Pre-Rules Framework
Document
Request
Yes, continue action
No
Get pre-rules class
Yes
Document.xml
Action
Data Dictionary Service
Pre-rules ok?
Get pre-rules class
Has pre-rules?
Plugging Pre-Rules
• Specify fully qualified class name for the Pre-rule implementation in the data dictionary XML file– Example: PaymentRequestDocument.xml
<preRulesCheckClass>
org.kuali.module.purap.rules.
PaymentRequestDocumentPreRules
</preRulesCheckClass>
PreRulesCheck Interface
public interface PreRulesCheck {
/** * Callback method from Maintenance action that allows
checks to be done and response redirected via the PreRulesCheckEvent
* * @param form * @param request * @param event * @return boolean indicating whether routing should
stop or continue */ public boolean processPreRuleChecks(ActionForm form,
HttpServletRequest request, PreRulesCheckEvent event);}
PreRulesContinuationBase
• This class simplifies 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
public abstract class PreRulesContinuationBase implements PreRulesCheck {
protected String question; protected String buttonClicked; protected PreRulesCheckEvent event; protected KualiForm form;
public abstract boolean doRules(Document document);
PreRulesContinuationBase
public boolean processPreRuleChecks(ActionForm form, HttpServletRequest request, PreRulesCheckEvent event) {
… try { result = doRules(event.getDocument()); } catch (IsAskingException e) { return false; } if (isAborting) { return false; } return result;}
PreRulesContinuationBase
PaymentRequestDocumentPreRules
/* Performs prompts and other pre business rule checks for the Payment request Document */
public class PaymentRequestDocumentPreRules extends AccountsPayableDocumentPreRulesBase {
… @Override public boolean doRules(Document document) { boolean preRulesOK = true; PaymentRequestDocument preq = (PaymentRequestDocument) document; if ((!
SpringContext.getBean(PurapService.class).isFullDocumentEntryCompleted(preq)) || (StringUtils.equals(preq.getStatusCode(), PurapConstants.PaymentRequestStatuses.AWAITING_ACCOUNTS_PAYABLE_REVIEW))) {
if (!confirmPayDayNotOverThresholdDaysAway(preq)) { return false; } } preRulesOK &= super.doRules(document); return preRulesOK; }
Summary
• System parameters– Provides on-the-fly configuration of certain
components– Provides business rules validations based on
matching values
• Authorizer – Determines who can initiate a document– How document fields are rendered & What
buttons are displayed
Summary
• “Pluggable” business rules– Java-based implementation of rules that are
more powerful than simple matching
• Pre-rules– Allows modification of form values prior to
processing– Allows “redirection” to a different page