It currently exists for a whole five business object classes in Chart of Accounts: Accounts, Object Codes, Account Delegates, Sub-Object Codes, and Organization Reversions. While largely similar to most other maintenance documents, there are a couple of differences to look at: global business objects must implement the GlobalBusinessObject method, they all have one or more collections of "details" (this is what makes them batch updates), and they must define a custom Maintainable.
- Implementing org.kuali.corerice.kns.bo.GlobalBusinessObject
- Detail collections
- Extending org.kuali.corerice.kns.maintenance.KualiGlobalMaintainableImpl
- A second look at generateGlobalChangesToPersist()
A global business object is, much like a transactional document class, a business object - it has references that can be refreshed, it can be persisted to a datastore - but it also shares qualities with documents. Unlike a regular maintenance document, which wraps a business object in the MaintenanceDocument class, the global business object is itself a document. It must declare a documentNumber, and tables for it and any associated "detail" objects must be created in the database along with OJB mappings. ojb-coa.xml has the OJB mapping for org.kuali.kfs.coa.businessobject.AccountGlobal, and that provides an excellent example of what a table mapping for a global business object will look like.
Global business objects must implement the org.kuali.corerice.kns.bo.GlobalBusinessObject interface. Let's take a tour of the methods we must implement:
- getDocumentNumber/setDocumentNumber: again, remember that the global business object is really a document. It needs a documentNumber so that workflow can track it through routing. The documentNumber will typically be the primary key of the global business object. Because of all of this, a getter and a setter for documentNumber are required for all global business objects.
- isPersistable: this tells the framework that the global maintenance document is in a state where it could persisted to the database or not. For instance, if some details within the document cannot be saved to the document, then isPersistable() should return false.
- getAllDetailObjects: This returns all of the detail objects associated with the global document. Even if there's multiple collections of detail objects, like there is for DelegateGlobal, all of the details from all collections need to be returned by this method.
- generateGlobalChangesToPersist and generateGlobalDeactivationsToPersist: Finally, we come to the methods that do the real work for Global Maintenance Documents. The purpose of global maintenance documents is to affect changes - insertions, updates, and deactivations - for many business objects. And these methods return Lists of PersistableBusinessObjects to perform these actions on. generateGlobalChangesToPersist() returns business objects that will be saved to the persistence store - so, any business object that should either be inserted or updated based on the global maintenance document should be returned here. generateGlobalDeactivationsToPersist(), on the other hand, is the reaper; any business objects returned by this method will be deactivated. We take a closer look at how to implement this in the section on generateGlobalChangesToPersist().
First, we have to create a class that extends org.kuali.corerice.kns.bo.GlobalBusinessObjectDetailBase. This class doesn't have much - just a document number, which acts as a foreign key to the global business object. The detail class can then have whatever methods it needs, typically getter/setter properties for the attributes that the user needs to enter. We also must create a database table to hold records of each type of detail business object and we have to set up the OJB mappings for the detail table.
Finally, in the global's data dictionary, the collection section of the details needs to be named after the property created in the last step. So, for instance, the property name of ObjectCodeGlobal's detail collection is "objectCodeGlobalDetails", and therefore, in the ObjectCodeGlobalMaintenanceDocument.xml data dictionary configuration file, we see this code:
<bean parent="MaintainableCollectionDefinition"> <property name="name" value="objectCodeGlobalDetails"/> <property name="businessObjectClass" value="org.kuali.kfs.coa.businessobject.ObjectCodeGlobalDetail"/> <property name="sourceClassName" value="org.kuali.kfs.coa.businessobject.Chart"/>
The collection is named after the property, and it uses the detail class as its business object class.
Global maintenance documents have a special maintainable implementation to extend, called KualiGlobalMaintainableImpl. It has a lot of utility methods for the maintenance of the global object, and we'll take a look at those in a second. However, it has one abstract method, which requires that we create an implementation for it: generateMaintenanceLocks(). Just as for non-global maintenance documents, this method creates a String representation of a business object to lock, so that no other user can edit that business object while the maintenance document is in workflow. While KualiMaintainableImpl can use an algorithm to generate those locks correctly most of the time, there's no way to do that for the global maintenance document, because the global maintenance document needs to generate a lock for every single business object that could be updated, inserted, or deactivated by the document. There, this method must be created. For examples of use, check out the existing global maintenance documents; for instance, org.kuali.kfs.coa.maintenancedocument.ObjectCodeGlobalMaintainableImpl has a very straightforward lock generation algorithm that can be adapted to the needs of different global maintenance documents.
- processGlobalsAfterRetrieve - called basically in place of KualiMaintainableImpl's processAfterRetrieve(), this is called after a global business object is retrieved from the persistence store. For an example, this is used by org.kuali.modulekfs.chartcoa.maintenancedocument.OrganizationReversionGlobalMaintainableImpl to prevent users from being able to add new organization reversion category records to the organization reversion.
- processGlobalsForSave - called before a global business object is saved. An example of this can be seen in org.kuali.modulekfs.chartcoa.maintenancedocument.ObjectCodeGlobalMaintainableImpl, where the object code details are all populated with the object code field from the ObjectCodeGlobal.
The trail ends here. Go back to the beginning, or leave your browser parked here and bask in the wisdom.