Fork me on GitHub

n. Slang a rough lawless young Kuali developer.
[perhaps variant of Houlihan, Irish surname]
kualiganism n

Blog of an rSmart Java Developer. Full of code examples, solutions, best practices, et al.

Friday, April 1, 2011

Constants Done with Spring

Kuali's Antipattern

The Rice pattern for handling constants in Kuali software is really an antipattern. It is basically an interface with public static final's. They chose an interface because it cannot be instantiated. This is an antipattern because it's not considered OO. An interface/class is created without the prospect of ever being instantiated or used for polymorphism. It's also inconsistent because as an interface is used at first, inner classes are used. Here's an example:
public class KFSConstants extends JSTLConstants implements ParameterKeyConstants {
private static final long serialVersionUID = 2882277719647128949L;

public static final String APPLICATION_NAMESPACE_CODE = "KFS";    

public static class ParameterNamespaces {
public static final String KFS = "KFS-SYS";
public static final String CHART = "KFS-COA";
public static final String FINANCIAL = "KFS-FP";
public static final String GL = "KFS-GL";
...
...
}
...
...

Now look at
public interface DisbursementVoucherConstants extends ParameterKeyConstants {

// Text limits
public static final int MAX_NOTE_LINE_SIZE = 90;

// payment methods
public static String PAYMENT_METHOD_CHECK = "P";
public static String PAYMENT_METHOD_WIRE = "W";
public static String PAYMENT_METHOD_DRAFT = "F";

// payee types
public static final String DV_PAYEE_TYPE_EMPLOYEE = "E";
public static final String DV_PAYEE_TYPE_VENDOR = "V";
public static final String DV_PAYEE_TYPE_CUSTOMER = "C";
public static final String DV_PAYEE_TYPE_SUBJECT_PAYMENT_VENDOR = "VSP";
public static final String DV_PAYEE_TYPE_REVOLVING_FUND_VENDOR = "VRF";

public static final List VENDOR_PAYEE_TYPE_CODES = Arrays.asList(DV_PAYEE_TYPE_VENDOR, DV_PAYEE_TYPE_SUBJECT_PAYMENT_VENDOR, DV_PAYEE_TYPE_REVOLVING_FUND_VENDOR);

// document location
public static final String NO_DOCUMENTATION_LOCATION = "N";

public static final String TAX_CONTROL_CODE_ALLOWS_EMPLOYEES = "A";
public static final String TAX_CONTROL_CODE_BEGIN_WITHHOLDING = "B";
public static final String TAX_CONTROL_CODE_HOLD_PAYMENT = "H";

public static class DocumentStatusCodes {
public static final String APPROVED = "A";
public static final String EXTRACTED = "E";
}
...
...
}

One is an class with another inner class. The other is an interface with an inner class. It's really inconsistent. Everyone does it differently.

Use Spring for Constants

I propose getting constants from Spring. Here is an example I used in the KIM Ldap Integration:

Create Constants Interface

package org.kuali.rice.kim.util;

import java.util.Collection;

import org.kuali.rice.kim.bo.entity.dto.KimEntityInfo;

/**
*
* @author Leo Przybylski (leo [at] rsmart.com)
*/ 
public interface Constants {    
Collection getTestPrincipalNames();

String getDefaultChartCode();

/**
* Gets the value of entityPrototype
*
* @return the value of entityPrototype
*/
KimEntityInfo getEntityPrototype();

/**
* Gets the value of externalIdTypeProperty
*
* @return the value of externalIdTypeProperty
*/
String getExternalIdTypeProperty();

/**
* Gets the value of taxExternalIdTypeCode
*
* @return the value of taxExternalIdTypeCode
*/
String getTaxExternalIdTypeCode();

/**
* Gets the value of externalIdProperty
*
* @return the value of externalIdProperty
*/
String getExternalIdProperty();

/**
* Gets the value of employeePhoneLdapProperty
*
* @return the value of employeePhoneLdapProperty
*/
String getEmployeePhoneLdapProperty();

/**
* Gets the value of employeeMailLdapProperty
*
* @return the value of employeeMailLdapProperty
*/
String getEmployeeMailLdapProperty();

/**
* Gets the value of defaultCountryCode
*
* @return the value of defaultCountryCode
*/
String getDefaultCountryCode();

/**
* Gets the value of personEntityTypeCode
*
* @return the value of personEntityTypeCode
*/
String getPersonEntityTypeCode();

/**
* Gets the value of uaidLdapProperty
*
* @return the value of uaidLdapProperty
*/
String getKimLdapIdProperty();

/**
* Gets the value of uidLdapProperty
*
* @return the value of uidLdapProperty
*/
String getKimLdapNameProperty();

/**
* Gets the value of snLdapProperty
*
* @return the value of snLdapProperty
*/
String getSnLdapProperty();

/**
* Gets the value of givenNameLdapProperty
*
* @return the value of givenNameLdapProperty
*/
String getGivenNameLdapProperty();

/**
* Gets the value of entityIdKimProperty
*
* @return the value of entityIdKimProperty
*/
String getEntityIdKimProperty();

/**
* Gets the value of parameterNamespaceCode
*
* @return the value of parameterNamespaceCode
*/
String getParameterNamespaceCode();

/**
* Gets the value of parameterDetailTypeCode
*
* @return the value of parameterDetailTypeCode
*/
String getParameterDetailTypeCode();

/**
* Gets the value of mappedParameterName
*
* @return the value of mappedParameterName
*/
String getMappedParameterName();

/**
* Gets the value of unmappedParameterName
*
* @return the value of unmappedParameterName
*/
String getUnmappedParameterName();

/**
* Gets the value of mappedValuesName
*
* @return the value of mappedValuesName
*/
String getMappedValuesName();

/**
* Gets the value of employeeIdProperty
*
* @return the value of employeeIdProperty
*/
String getEmployeeIdProperty();

/**
* Gets the value of departmentLdapProperty
*
* @return the value of departmentLdapProperty
*/
String getDepartmentLdapProperty();

/**
* Gets the value of employeeTypeProperty
*
* @return the value of employeeTypeProperty
*/
String getEmployeeTypeProperty();

/**
* Sets the value of employeeTypeProperty
*
* @param argEmployeeTypeProperty Value to assign to this.employeeTypeProperty
*/
void setEmployeeTypeProperty(String argEmployeeTypeProperty);

/**
* Gets the value of employeeStatusProperty
*
* @return the value of employeeStatusProperty
*/
String getEmployeeStatusProperty();

/**
* Sets the value of employeeStatusProperty
*
* @param argEmployeeStatusProperty Value to assign to this.employeeStatusProperty
*/
void setEmployeeStatusProperty(String argEmployeeStatusProperty);

/**
* Gets the value of defaultCampusCode
*
* @return the value of defaultCampusCode
*/
String getDefaultCampusCode();

/**
* Sets the value of defaultCampusCode
*
* @param argDefaultCampusCode Value to assign to this.defaultCampusCode
*/
void setDefaultCampusCode(String argDefaultCampusCode);

/**
* Gets the value of the employee affiliation code
* 
* @return the value of employeeAffiliationCode
*/
String getEmployeeAffiliationCodes();

/** 
* Gets the mappings between LDAP and KIM affiliations
* @return mappings of the form "staff=STAFF,affiliate=AFLT"
*/
String getAffiliationMappings();
}

Notice, there are only get methods. You'll see easier in a second, but this is how we get Spring beans to be read-only and constants.

Create the Constants Implementation

It's just going to be a pojo. We can easily put this within the the original interface as an inner class since it's just spring that's going to use it.
/**
* KIM Related Constants Implementation
*
* @author Leo Przybylski (leo [at] rsmart.com)
*/ 
static class ConstantsImpl implements Constants {    
private Collection testPrincipalNames;
private KimEntityInfo entityPrototype;
private String externalIdTypeProperty;
private String taxExternalIdTypeCode;
private String externalIdProperty;
private String employeePhoneLdapProperty;
private String employeeMailLdapProperty;
private String defaultCountryCode;
private String personEntityTypeCode;
private String kimLdapIdProperty;
private String kimLdapNameProperty;
private String snLdapProperty;
private String givenNameLdapProperty;
private String entityIdKimProperty;
private String parameterNamespaceCode;
private String parameterDetailTypeCode;
private String mappedParameterName;
private String unmappedParameterName;
private String mappedValuesName;
private String employeeIdProperty;
private String departmentLdapProperty;
private String employeeTypeProperty;
private String employeeStatusProperty;
private String defaultCampusCode;
private String defaultChartCode;
private String employeeAffiliationCodes;
private String affiliationMappings;

public Collection getTestPrincipalNames() {
return testPrincipalNames;
}

public void setTestPrincipalNames(Collection testPrincipalNames) {
this.testPrincipalNames = testPrincipalNames;
}

/**
* Gets the value of entityPrototype
*
* @return the value of entityPrototype
*/
public KimEntityInfo getEntityPrototype() {
// return this.entityPrototype;
return (KimEntityInfo) getService("entityPrototype");
// return (KimEntityDefaultInfo) getService("entityPrototype");
}

/**
* Sets the value of entityPrototype
*
* @param argEntityPrototype Value to assign to this.entityPrototype
*/
public void setEntityPrototype(KimEntityInfo argEntityPrototype) {
this.entityPrototype = argEntityPrototype;
}

/**
* Gets the value of externalIdTypeProperty
*
* @return the value of externalIdTypeProperty
*/
public String getExternalIdTypeProperty() {
return this.externalIdTypeProperty;
}

/**
* Sets the value of externalIdTypeProperty
*
* @param argExternalIdTypeProperty Value to assign to this.externalIdTypeProperty
*/
public void setExternalIdTypeProperty(String argExternalIdTypeProperty) {
this.externalIdTypeProperty = argExternalIdTypeProperty;
}

/**
* Gets the value of taxExternalIdTypeCode
*
* @return the value of taxExternalIdTypeCode
*/
public String getTaxExternalIdTypeCode() {
return this.taxExternalIdTypeCode;
}

/**
* Sets the value of taxExternalIdTypeCode
*
* @param argTaxExternalIdTypeCode Value to assign to this.taxExternalIdTypeCode
*/
public void setTaxExternalIdTypeCode(String argTaxExternalIdTypeCode) {
this.taxExternalIdTypeCode = argTaxExternalIdTypeCode;
}

/**
* Gets the value of externalIdProperty
*
* @return the value of externalIdProperty
*/
public String getExternalIdProperty() {
return this.externalIdProperty;
}

/**
* Sets the value of externalIdProperty
*
* @param argExternalIdProperty Value to assign to this.externalIdProperty
*/
public void setExternalIdProperty(String argExternalIdProperty) {
this.externalIdProperty = argExternalIdProperty;
}

/**
* Gets the value of employeePhoneLdapProperty
*
* @return the value of employeePhoneLdapProperty
*/
public String getEmployeePhoneLdapProperty() {
return this.employeePhoneLdapProperty;
}

/**
* Sets the value of employeePhoneLdapProperty
*
* @param argEmployeePhoneLdapProperty Value to assign to this.employeePhoneLdapProperty
*/
public void setEmployeePhoneLdapProperty(String argEmployeePhoneLdapProperty) {
this.employeePhoneLdapProperty = argEmployeePhoneLdapProperty;
}

/**
* Gets the value of employeeMailLdapProperty
*
* @return the value of employeeMailLdapProperty
*/
public String getEmployeeMailLdapProperty() {
return this.employeeMailLdapProperty;
}

/**
* Sets the value of employeeMailLdapProperty
*
* @param argEmployeeMailLdapProperty Value to assign to this.employeeMailLdapProperty
*/
public void setEmployeeMailLdapProperty(String argEmployeeMailLdapProperty) {
this.employeeMailLdapProperty = argEmployeeMailLdapProperty;
}

/**
* Gets the value of defaultCountryCode
*
* @return the value of defaultCountryCode
*/
public String getDefaultCountryCode() {
return this.defaultCountryCode;
}

/**
* Sets the value of defaultCountryCode
*
* @param argDefaultCountryCode Value to assign to this.defaultCountryCode
*/
public void setDefaultCountryCode(String argDefaultCountryCode) {
this.defaultCountryCode = argDefaultCountryCode;
}

/**
* Gets the value of personEntityTypeCode
*
* @return the value of personEntityTypeCode
*/
public String getPersonEntityTypeCode() {
return this.personEntityTypeCode;
}

/**
* Sets the value of personEntityTypeCode
*
* @param argPersonEntityTypeCode Value to assign to this.personEntityTypeCode
*/
public void setPersonEntityTypeCode(String argPersonEntityTypeCode) {
this.personEntityTypeCode = argPersonEntityTypeCode;
}

/**
* Sets the value of kimLdapIdProperty
*
* @param kimLdapIdProperty value to set
*/
public void setKimLdapIdProperty(String kimLdapIdProperty) {
this.kimLdapIdProperty = kimLdapIdProperty;
}

/**
* Gets the value of kimLdapIdProperty
*
* @return the value of kimLdapIdProperty
*/
public String getKimLdapIdProperty() {
return kimLdapIdProperty;
}

/**
* Gets the value of kimLdapNameProperty
*
* @param kimLdapNameProperty the value of kimLdapNameProperty
*/
public void getKimLdapNameProperty(String kimLdapNameProperty) {
this.kimLdapNameProperty = kimLdapNameProperty;
}

/**
* Gets the value of kimLdapNameProperty
*
* @return the value of kimLdapNameProperty
*/
public String getKimLdapNameProperty() {
return kimLdapNameProperty;
}

/**
* Gets the value of snLdapProperty
*
* @return the value of snLdapProperty
*/
public String getSnLdapProperty() {
return this.snLdapProperty;
}

/**
* Sets the value of snLdapProperty
*
* @param argSnLdapProperty Value to assign to this.snLdapProperty
*/
public void setSnLdapProperty(String argSnLdapProperty) {
this.snLdapProperty = argSnLdapProperty;
}

/**
* Gets the value of givenNameLdapProperty
*
* @return the value of givenNameLdapProperty
*/
public String getGivenNameLdapProperty() {
return this.givenNameLdapProperty;
}

/**
* Sets the value of givenNameLdapProperty
*
* @param argGivenNameLdapProperty Value to assign to this.givenNameLdapProperty
*/
public void setGivenNameLdapProperty(String argGivenNameLdapProperty) {
this.givenNameLdapProperty = argGivenNameLdapProperty;
}

/**
* Gets the value of entityIdKimProperty
*
* @return the value of entityIdKimProperty
*/
public String getEntityIdKimProperty() {
return this.entityIdKimProperty;
}

/**
* Sets the value of entityIdKimProperty
*
* @param argEntityIdKimProperty Value to assign to this.entityIdKimProperty
*/
public void setEntityIdKimProperty(String argEntityIdKimProperty) {
this.entityIdKimProperty = argEntityIdKimProperty;
}

/**
* Gets the value of parameterNamespaceCode
*
* @return the value of parameterNamespaceCode
*/
public String getParameterNamespaceCode() {
return this.parameterNamespaceCode;
}

/**
* Sets the value of parameterNamespaceCode
*
* @param argParameterNamespaceCode Value to assign to this.parameterNamespaceCode
*/
public void setParameterNamespaceCode(String argParameterNamespaceCode) {
this.parameterNamespaceCode = argParameterNamespaceCode;
}

/**
* Gets the value of parameterDetailTypeCode
*
* @return the value of parameterDetailTypeCode
*/
public String getParameterDetailTypeCode() {
return this.parameterDetailTypeCode;
}

/**
* Sets the value of parameterDetailTypeCode
*
* @param argParameterDetailTypeCode Value to assign to this.parameterDetailTypeCode
*/
public void setParameterDetailTypeCode(String argParameterDetailTypeCode) {
this.parameterDetailTypeCode = argParameterDetailTypeCode;
}

/**
* Gets the value of mappedParameterName
*
* @return the value of mappedParameterName
*/
public String getMappedParameterName() {
return this.mappedParameterName;
}

/**
* Sets the value of mappedParameterName
*
* @param argMappedParameterName Value to assign to this.mappedParameterName
*/
public void setMappedParameterName(String argMappedParameterName) {
this.mappedParameterName = argMappedParameterName;
}

/**
* Gets the value of unmappedParameterName
*
* @return the value of unmappedParameterName
*/
public String getUnmappedParameterName() {
return this.unmappedParameterName;
}

/**
* Sets the value of unmappedParameterName
*
* @param argUnmappedParameterName Value to assign to this.unmappedParameterName
*/
public void setUnmappedParameterName(String argUnmappedParameterName) {
this.unmappedParameterName = argUnmappedParameterName;
}

/**
* Gets the value of mappedValuesName
*
* @return the value of mappedValuesName
*/
public String getMappedValuesName() {
return this.mappedValuesName;
}

/**
* Sets the value of mappedValuesName
*
* @param argMappedValuesName Value to assign to this.mappedValuesName
*/
public void setMappedValuesName(String argMappedValuesName) {
this.mappedValuesName = argMappedValuesName;
}

/**
* Gets the value of employeeIdProperty
*
* @return the value of employeeIdProperty
*/
public String getEmployeeIdProperty() {
return this.employeeIdProperty;
}

/**
* Sets the value of employeeIdProperty
*
* @param argEmployeeIdProperty Value to assign to this.employeeIdProperty
*/
public void setEmployeeIdProperty(String argEmployeeIdProperty) {
this.employeeIdProperty = argEmployeeIdProperty;
}

/**
* Gets the value of departmentLdapProperty
*
* @return the value of departmentLdapProperty
*/
public String getDepartmentLdapProperty() {
return this.departmentLdapProperty;
}

/**
* Sets the value of departmentLdapProperty
*
* @param argDepartmentLdapProperty Value to assign to this.departmentLdapProperty
*/
public void setDepartmentLdapProperty(String argDepartmentLdapProperty) {
this.departmentLdapProperty = argDepartmentLdapProperty;
}

/**
* Gets the value of employeeTypeProperty
*
* @return the value of employeeTypeProperty
*/
public String getEmployeeTypeProperty() {
return this.employeeTypeProperty;
}

/**
* Sets the value of employeeTypeProperty
*
* @param argEmployeeTypeProperty Value to assign to this.employeeTypeProperty
*/
public void setEmployeeTypeProperty(String argEmployeeTypeProperty) {
this.employeeTypeProperty = argEmployeeTypeProperty;
}

/**
* Gets the value of employeeStatusProperty
*
* @return the value of employeeStatusProperty
*/
public String getEmployeeStatusProperty() {
return this.employeeStatusProperty;
}

/**
* Sets the value of employeeStatusProperty
*
* @param argEmployeeStatusProperty Value to assign to this.employeeStatusProperty
*/
public void setEmployeeStatusProperty(String argEmployeeStatusProperty) {
this.employeeStatusProperty = argEmployeeStatusProperty;
}

/**
* Gets the value of defaultCampusCode
*
* @return the value of defaultCampusCode
*/
public String getDefaultCampusCode() {
return this.defaultCampusCode;
}

/**
* Sets the value of defaultCampusCode
*
* @param argDefaultCampusCode Value to assign to this.defaultCampusCode
*/
public void setDefaultCampusCode(String argDefaultCampusCode) {
this.defaultCampusCode = argDefaultCampusCode;
}


public void setDefaultChartCode(String chartCode) {
this.defaultChartCode = chartCode;
}

public String getDefaultChartCode() {
return defaultChartCode;
}

public String getEmployeeAffiliationCodes() {
return employeeAffiliationCodes;
}

public void setEmployeeAffiliationCodes(String employeeAffiliationCodes) {
this.employeeAffiliationCodes = employeeAffiliationCodes;
}

public String getAffiliationMappings() {
return affiliationMappings;
}

public void setAffiliationMappings(String affiliationMappings) {
this.affiliationMappings = affiliationMappings;
}
}

It is static, so it can be instantiated, but it's also package level. This is important. Now, normal classes cannot just instantiate a Constants instance and override spring programmatically. Spring can still instantiate it and set it at startup though, so we are safe. Spring can instantiate and spring only.

Define the Constants Bean in Spring

Now let us set our constants



...
...

















  










...
...


Inject the Constants Bean into a Service

There, now the Constants is instantiated and stored in Spring as a bean. We can now easily inject this into other classes that need it.
*lt;bean id="ldapPrincipalDao" class="org.kuali.rice.kim.dao.impl.LdapPrincipalDaoImpl">
<property name="ldapTemplate"     ref="ldapTemplate" />
<property name="parameterService" ref="parameterService" />
<property name="kimConstants"     ref="kimConstants" />
...
...

Now use it

Here is an example of the usage:
String affiliationCode = getAffiliationTypeCodeForName(primaryAffiliation);
KimEntityAffiliationInfo aff1 = new KimEntityAffiliationInfo();
aff1.setAffiliationTypeCode(affiliationCode == null ? "AFLT" : affiliationCode);
aff1.setCampusCode(getConstants().getDefaultCampusCode());
aff1.setEntityAffiliationId("" + affiliationId++);
aff1.setDefault(true);
aff1.setActive(true);

Use Without Injection

...
String affiliationCode = getAffiliationTypeCodeForName(primaryAffiliation);
KimEntityAffiliationInfo aff1 = new KimEntityAffiliationInfo();
aff1.setAffiliationTypeCode(affiliationCode == null ? "AFLT" : affiliationCode);
aff1.setCampusCode(getConstants().getDefaultCampusCode());
aff1.setEntityAffiliationId("" + affiliationId++);
aff1.setDefault(true);
aff1.setActive(true);
...
public Constants getConstants() {
return SpringContext.getService("kimConstants");
}

That's it! I found this very useful when needing to change constants or finding what the values of constants are. The public static final boiler plate always makes it difficult to read, and the inner classes really make things a mess.

No comments:

Post a Comment