|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 6 of 6
Step 2. Invoke the Castor schema compiler to generate Java classes
First, we need to set the CLASSPATH to include:
castor-0.9.3-xml.jar: Castor classes
xerces.jar: Apache Xerces2 XML parser
jakarta-regexp-1.2.jar: Jakarta regexp package
Next, we run the Castor schema compiler:
java org.exolab.castor.builder.SourceGenerator -i socks.xsd -dest destination_directory
So, the XML Schema goes in, and Java classes come out. The Java files produced are Socks.java, SocksDescriptor, Sock.java, SockDescriptor.java, ColorType.java, and ColorTypeDescriptor.java.
The marshaling framework uses the class descriptors to hold binding and validation information. We won't work with these directly.
Also notice that the ColorType classes are put into a package called types. Those classes are in the types package because we used an enumeration to restrict the possible color values to white and black. Castor makes custom types to handle validation with that sort of constraint.
Look at the generated Java files. In particular, look for the marshal(), unmarshal(), and validate() methods in the main classes. In SockDescriptor.java, look for the regular expressions from socks.xsd, like "(.)+\\.(gif|jpg|jpeg|bmp)". Again, validation occurs in the Descriptor classes.
The Castor source generator features many more options we haven't discussed. See the Resources for further reading.
Step 3. Compile our newly generated classes
Compile the generated classes.
Step 4. Examine a test program similar to the last one using these classes
Now we'll write a program to use our newly generated classes; it's going to clean my socks. The program is a bit complex,
but guaranteed to be more fun than real laundry. The strategy is to unmarshal a socks.xml document, extract the socks, set their smell to 0 (clean), and add a new sock:
Listing 8. CastorTestSocks.java
import java.io.*;
import java.util.*;
import java.math.BigDecimal;
import org.exolab.castor.xml.*;
import org.exolab.castor.xml.util.*;
public class CastorSocksTest {
public static void main(String[] args) {
try {
System.out.println("Unmarshaling Socks");
//pass in socks.xml as a command-line argument Socks socksDocument = Socks.unmarshal(new FileReader(args[0]));
//Get all socks and print out their attributes Sock[] sockArray = socksDocument.getSock();
printSocks(sockArray);
//Wash all socks (set smell to 0)
System.out.println("Cleaning socks by setting smell to 0"); for (int x=0;x<sockArray.length;x++) {
sockArray[x].setSmell(0);
}
printSocks(sockArray);
//Marshal
System.out.println("Marshaling socks to file cleanSocks.xml"); socksDocument.validate(); //make sure the sock is valid against the schema
socksDocument.marshal(new FileWriter("cleanSocks.xml"));
//Make a new sock
System.out.println("Make a new sock"); Sock newSock = new Sock();
newSock.setNumber("4"); // Actually setting an attribute!
newSock.setName("New Sock");
//Castor created a package called types for the ColorType class
newSock.setColor(types.ColorType.BLACK);
newSock.setPrice(new BigDecimal("3.33"));
newSock.setSmell(2); // I think new sock smell is a 2
newSock.setImage("newsock.jpg");
//add new sock to in memory Socks object (unmarshaled XML doc) socksDocument.addSock(newSock);
//Ask it for a new array with all contained socks
Sock[] sockArray2 = socksDocument.getSock();
printSocks(sockArray2);
System.out.println("Marshaling socks to file socksPlusNewSock.xml"); socksDocument.validate(); //make sure the sock is valid against the schema
socksDocument.marshal(new FileWriter("socksPlusNewSock.xml"));
} catch (ValidationException ve) {
System.out.println(ve.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
//Helper method to print out the socks
static void printSocks(Sock[] sockArray) {
System.out.println("Printing in memory socks...");
Sock currentSock;
for (int x=0;x<sockArray.length;x++) {
currentSock=sockArray[x];
System.out.println("Sock number " + currentSock.getNumber() +
" | Name: " + currentSock.getName() +
" | Color: " + currentSock.getColor() +
" | Price: " + currentSock.getPrice() +
" | Smell: " + currentSock.getSmell());
}
System.out.println("");
}
}
Steps 4a and 4b. Unmarshal and change the content tree
This goes somewhat similarly to our JAXBSocksTest. Notice the differences, particularly the use of a static unmarshal method. Also notice we're working with Arrays here instead of Lists.
Steps 4c and 4d. Validate and marshal
This code also resembles JAXBSocksTest.
Step 5. Compile and run the test program
Compile and run the test program.
Here is the output:
Listing 9. CastorTestSocks Output
Unmarshaling Socks Printing in memory socks... Sock number 1 | Name: black socks | Color: black | Price: 9.99 | Smell: 7 Sock number 2 | Name: white socks | Color: white | Price: 5.34 | Smell: 2 Sock number 3 | Name: old white socks | Color: white | Price: 2.20 | Smell: 9 Cleaning socks by setting smell to 0 Printing in memory socks... Sock number 1 | Name: black socks | Color: black | Price: 9.99 | Smell: 0 Sock number 2 | Name: white socks | Color: white | Price: 5.34 | Smell: 0 Sock number 3 | Name: old white socks | Color: white | Price: 2.20 | Smell: 0 Marshaling socks to file cleanSocks.xml Make a new sock Printing in memory socks... Sock number 1 | Name: black socks | Color: black | Price: 9.99 | Smell: 0 Sock number 2 | Name: white socks | Color: white | Price: 5.34 | Smell: 0 Sock number 3 | Name: old white socks | Color: white | Price: 2.20 | Smell: 0 Sock number 4 | Name: New Sock | Color: black | Price: 3.33 | Smell: 2 Marshaling socks to file socksPlusNewSock.xml
Clean socks saved to disk. What a relief!
For a full code listing and detailed instructions on running this example, download my code from Resources.
JAXB and Castor are both frameworks that automatically construct a bridge between Java programs and XML documents. Programmers can use JAXB or Castor to represent constrained XML documents as Java objects. With this automatic access to XML data, you need to write only the applications that will actually use the XML data -- and no code to retrieve, validate, or save the data. Since you specify data validation constraints in the DTD or XML Schema definition, and not in your Java code, your program is more maintainable. And because you use in-memory objects instead of slow XML parsing code, your program is inherently faster.
That's the scoop on JAXB and its older brother, Castor. Automating the Java class creation based on XML data constraints should save you some precious programming time and buy you some maintainability. Besides, you won't have to hire a summer intern or do your own laundry this year! To make your Java programming life even easier, keep an eye on both JAXB and Castor for the next wave of exciting advances.
Read more about Enterprise Java in JavaWorld's Enterprise Java section.