- A Staff Management System
- Two Employee Types
- The Apache Jakarta Commons Digester Code Deployment Model
- The HR Director Needs an Upgrade
- Upgrade Deployment
- A More Generalized Upgrade Approach
- Are Upgrade Mechanisms a Thing of the Past?
- Conclusions
- Resources
The Apache Jakarta Commons Digester Code Deployment Model
Given that I want to illustrate role-based IT management and dynamic upgrading, let’s now take a look at a mechanism for automatically creating the above Java classes from XML. This is done by unmarshalling the following XML document.
Notice that the XML tags correspond with the above class and subclass names and the associated data member names. For example, the tag <permanentstaff> matches the name of the subclass PermanentStaff. Once this tag is encountered during parsing, an object of the PermanentStaff class is instantiated with its data members set to the values indicated in the tags below it: <personName> and <socialSecurityNumber>. The XML file is well-formed, so all tags consist of start and end elements: <socialSecurityNumber> and </socialSecurityNumber>.
<?xml version="1.0"?> <hrstaffdetails company="company"> <permanentstaff> <personName>Francis Bacon</personName> <socialSecurityNumber>1111111</socialSecurityNumber> </permanentstaff> <permanentstaff> <personName>Francesca Bacon</personName> <socialSecurityNumber>2222222</socialSecurityNumber> </permanentstaff> <contractstaff> <personName>Francisco Bacon</personName> <socialSecurityNumber>3333333</socialSecurityNumber> </contractstaff> </hrstaffdetails>
This is the key to using the Commons Digester: You can parse the XML files and create instances of arbitrarily complex class structures. This is a powerful facility because it allows for the flexible creation of objects in a location-independent fashion.
In other words, if I want to create an object of class A on machine X, I can simply define the XML file and run the Digester against it. The result is a newly instantiated object where I want it, when I want it.
I’ll be using this mechanism a little later to show how to upgrade classes. Again, this is just another case of using the flexibility of the Digester mechanism.
The Commons Digester class is used to process the above XML document based on the following patterns and rules:
<?xml version="1.0"?> <digester-rules> <object-create-rule pattern="hrstaffdetails" classname="HRStaffDetails" /> <set-properties-rule pattern="hrstaffdetails" > <alias attr-name="company" prop-name="company" /> </set-properties-rule> <pattern value="hrstaffdetails/permanentstaff"> <object-create-rule classname="PermanentStaff" /> <call-method-rule pattern="personName" methodname="setPersonName" paramcount="0" /> <call-method-rule pattern="socialSecurityNumber" methodname="setSocialSecurityNumber" paramcount="0" /> <set-next-rule methodname="addPermanentStaff" /> </pattern> <pattern value="hrstaffdetails/contractstaff"> <object-create-rule classname="ContractStaff" /> <call-method-rule pattern="personName" methodname="setPersonName" paramcount="0" /> <call-method-rule pattern="socialSecurityNumber" methodname="setSocialSecurityNumber" paramcount="0" /> <set-next-rule methodname="addContractor" /> </pattern> </digester-rules>
The above looks very complicated, but it’s really not! Let’s break it down a bit. The object-create-rule is invoked when the pattern hrstaffdetails is encountered. When this occurs, an object of the class HRStaffDetails is instantiated.
The next rule sets the properties of the class; in this case a company name is set. The next rule is called a pattern value and serves to create an instance of the class PermanentStaff.
The contained rule call-method-rule is used to invoke the base class method setPersonName, using the <personName> rule from the previous XML file.
The same mechanism occurs for the socialSecurityNumber pattern. The last rule for the PermanentStaff class is called set-next-rule, which in this case refers to the method HRStaffDetails.addPermanentStaff.
This completes the first part of unmarshalling an instance of HRStaffDetails. The rest of HRStaffDetails is unmarshalled using the remainder of the rules. The latter apply to the class ContractStaff and operate in a manner identical to that for the class PermanentStaff.
The last piece of the puzzle is the class that creates the Digester:
import org.apache.commons.digester.*; import org.apache.commons.digester.xmlrules.*; import java.io.*; import java.util.*; public class XmlRulesDriver { public static void main(String[] args) { try { File input = new File(args[0]); File rules = new File(args[1]); Digester digester = DigesterLoader.createDigester(rules.toURL()); HRStaffDetails staffDetails = (HRStaffDetails)digester.parse(input); System.out.println(staffDetails.toString()); } catch(Exception e) { e.printStackTrace(); } } }
The above code reads the two XML files described earlier, namely hrstaffdetails.xml and rules.xml. Then, an instance of Digester is created, into which the file rules.xml is passed.
The Digester then parses the file hrstaffdetails.xml in conjunction with the rules file to produce an instance of the class HRStaffDetails.
All you need to get the code built are the following:
- The above five Java classes
- A copy of the commons-digester JAR file in your classpath
Specifically, you may find you’ll need the following JAR files in your CLASSPATH:
- commons-digester-1.7.jar
- commons-collections-3.2.jar
- commons-logging-api-1.1.jar
- commons-beanutils-core.jar
To manually run the program, type this command:
java XmlRulesDriver hrstaffdetails.xml rules.xml
The above command should produce the output displayed earlier in Figure 3. There is also a batch file (called ToRun.bat) supplied with the code to help you run the program.
Let’s now go back to Figure 3 and assume that the view in Figure 3 is that of all users—privileged and non-privileged.
Our HR director now decides that access is required to salary data. We want to be able to display salary and hourly rate details for the HR director as per Figure 2.