Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Dynamically manage XML schema variations in XMLBeans applications

Use dynamic class loading to overcome processing limitations in XMLBeans

Abdul Rasid (abdul.rasid@in.ibm.com), Systems Software Engineer, IBM
Photo of Abdul Rasid
Abdul Rasid is a System Software Engineer with IBM India Software Labs, Bangalore. He currently works on the WebSphere RFID Information Center development team.
Pallavi Rao (npallavi@in.ibm.com), Advisory Software Engineer, Systems Documentation, Inc. (SDI)
Photo of Pallavi Nagesha Rao
Pallavi Nagesha Rao has worked in the IT industry for over eight years in a variety of roles, including the development of J2EE applications, transaction management systems (TXSeries), and information management systems. Currently, she leads the WebSphere RFID Information Center development at India Software Labs. She has also authored other developerWorks articles and Redbooks.

Summary:  Apache XMLBeans does not inherently support multiple versions of an XML schema. For applications that need this type of support to manage compatibility, this limitation is serious. But there is a solution, and in this article, you'll learn how dynamic class loading techniques can help.

Date:  26 Aug 2008
Level:  Introductory PDF:  A4 and Letter (49 KB)Get Adobe® Reader®
Also available in:   Chinese

Activity:  19660 views
Comments:  

Apache XMLBeans is an open source, XML- and Java™-binding tool used to generate Java classes and interfaces from an XML schema. With the generated beans, you can parse or generate XML documents that conform to the schema. Consequently, this binding causes a very tight coupling between the generated Java classes and the XML schema. When you make minor or major changes to the XML schema, the beans are regenerated and the new beans corresponding to the changed XML schema are used. At least, this is how it's intended to work. Unfortunately, sometimes an application needs to support multiple versions of a schema. For example, in the case where XML is used as a standard for data exchange, the application must provide backward or forward compatibility to older or newer versions of the standard.

Setting the stage

Frequently used acronyms

  • JRE: Java Runtime Environment
  • JVM: Java Virtual Machine
  • SAX: Simple API For XML
  • URL: Uniform Resource Locator
  • XML: Extensible Markup Language
  • XSD: XML Schema Definition

Consider an employee data management application, in which the application takes the employee information in the form of an XML file and uses Apache XMLBeans to process it. The employee data has been defined by an XSD, shown in Listing 1. This schema is compiled with the XMLBeans schema compiler. The application then uses the generated Java classes and interfaces to process an incoming XML document that is compliant to the XSD with the namespace com.ibm.sample.employee:1.


Listing 1. First version of the employee XML schema
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="com.ibm.sample.employee:1" elementFormDefault="qualified" 
  xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="com.ibm.sample.employee:1">

    <element name="employee" type="tns:employeeType"></element>
    
    <complexType name="employeeType">
        <sequence>
            <element name="firstName" type="string"></element>
            <element name="lastName" type="string"></element>
            <element name="department" type="string"></element>
            <element name="phone" type="string"></element>
            <element name="eEmail" type="string"></element>
        </sequence>
    </complexType>
</schema>

Listing 2 shows the application that processes the employee XML, and Listing 3 shows the client application that uses it:


Listing 2. The XMLBeans application
public class EmployeeApplication {

    public void parseXML(String xmlFileName){

        EmployeeDocument employeeDoc = 
EmployeeDocument.Factory.parse(new File(xml));
            EmployeeType employee = employeeDoc.getEmployee();
            System.out.println(employee.getFirstName());
            // Do something more useful with the employee data

    }
}


Listing 3. The client
    EmployeeApplication app = new EmployeeApplication();
    app.parseXML(xmlFilePath);

Introducing schema changes

Now assume the schema is modified, and the Java beans generated for the old schema can no longer use the new schema to process the XML. Listing 4 shows the changed schema with some new elements added, and the namespace changed to com.ibm.sample.employee:2 to indicate it is the second version.


Listing 4. Second version of the employee XML schema
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="com.ibm.sample.employee:2" elementFormDefault="qualified" 
  xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="com.ibm.sample.employee:2">

    <element name="employee" type="tns:employeeType"></element>

    <complexType name="employeeType">
        <sequence>
            <element name="firstName" type="string"></element>
            <element name="lastName" type="string"></element>
            <element name="dept" type="string"></element>
            <element name="eMail" type="string"></element>
            <element name="phone" type="string"></element>
<element name="address" type="tns:addressType"></element>
        </sequence>
    </complexType>

    <complexType name="addressType">
        <sequence>
            <element name="streetName" type="string"></element>
            <element name="houseNumber" type="string"></element>
            <element name="city" type="string"></element>
            <element name="state" type="string"></element>
            <element name="zipCode" type="string"></element>
        </sequence>
    </complexType>
</schema>

To ensure forward compatibility, you don't want to modify the client application. However, some sources of the input XML have upgraded to the new schema, so the application must be able to process incoming employee XML data with either namespace. But XMLBeans can't manage the competing schemas, so what can you do?

Overcoming the processing limitation

For the application to be able to process the new XML schema, you'll have to generate a new set of Java beans that corresponds to the new schema. Because you do not wish to alter the application, you need to make sure the new Java beans generated by Apache XMLBeans have the same package names as the old ones. That way, the application can use these beans without any change in the code. Map both the com.ibm.sample.employee:1 and com.ibm.sample.employee:2 namespaces to a single Java package, such as com.ibm.sample.employee. (Mapping is outside the scope of this article; see Resources for more information.)

Once you have different sets of Java beans to correspond to the different schemas, all you do is load the appropriate one depending on the incoming XML. You can use dynamic class loading techniques to ensure the correct set of beans is loaded. The following sections show how to use the proxy pattern and Java class loading to load multiple versions of the XMLBeans corresponding to each of the schemas.

Java class loading

In Java programming, class loaders are first-class objects and have their own namespace. A class loaded by a class loader instance is uniquely identified by that class loaders namespace and the class name. For example, suppose you have a class loader called MyClassLoader. If an instance of this class loader, myLoaderA, loads a class Foo, and the same class Foo is also loaded by another instance, myLoaderB, the JVM treats the class Foo as two different classes and loads it twice (see Figure 1).


Figure 1. Java class loading
Java class loading

Java class loading uses a delegation model to load the classes. Every class loader has a parent class loader, which delegates the searching and loading of a class to its parent (parent-first delegation) before it attempts to load the class itself. When there is a hierarchy of class loaders, the root class loader, which is the bootstrap class loader, attempts to load the class first. If it cannot, its child, the system class loader, tries to load it, and so on. (See Resources for more information on Java class loading.)

To process two different schema versions, you will create different class loader instances and have each one of them load the application and a version of the Java beans, corresponding to an XML schema.

The proxy

Next, you will create a proxy with the same public interface as the original application or bean. The proxy will create one instance of a class loader for each XML schema version. The parent of this class loader will be the class loader of the current thread context. Based on the schema of the XML being processed, this proxy will use the appropriate instance of the class loader to load the Java beans corresponding to each XSD and the application itself. The reason for loading the application multiple times is that when the JVM attempts to load all the classes used by the application, it looks for them in the same namespace. If it doesn't find these classes in the same namespace, it throws a ClassNotFound exception. Figure 2 shows how the proxy works:


Figure 2. Dynamic loading of the XMLBeans by the proxy
Figure 2. Dynamic loading of the XMLBeans by the proxy

The proxy can use the namespace of the received XML to decide which XMLBeans to load, or the XML can have an element that will indicate the version of the XSD. The proxy can then use a simple SAX parser to retrieve this information.

Sample application processing multiple schema versions

Revisit the employee data management application. Listing 5 shows the proxy code:


Listing 5. The proxy
/* These are class variables as only one set of instances of the
     *  class loaders are required.
     *  Using instance variables will only proliferate the class loaders and
     *  the classes loaded by them.
*/
   private static URLClassLoader ccl1 = null, ccl2 = null;

   private URLClassLoader createURLClassLoader(URL url){

      ClassLoader parent = Thread.currentThread().getContextClassLoader();
      URLClassLoader ucl = new URLClassLoader(new URL[]{applicationJarURL,url},
                                  parent);
                return ucl;

   }

   private URLClassLoader loadXMLBeans(int choice) {
      try{
         switch (choice){
            case 1:
               if ( ccl1 == null){
                  ccl1 = createURLClassLoader(
                     new URL("file",null,jarPath+"employee1.jar"));
               }
               return ccl1;
            // Load the latest by default
            default :
            case 2:
               if ( ccl2 == null){
                  ccl2 = createURLClassLoader(
                     new URL("file",null,jarPath+"employee2.jar"));
               }
               return ccl2;

   }

   public void parseXML(String xmlFileName){
      try {
         // Determine which version of XML schema is being used.

         URLClassLoader ccl = loadXMLBeans(choice);

         Class c = ccl.loadClass(
                           "com.ibm.sample.application.employee.EmployeeApplication");
         Class s = String.class;
         Object obj = c.newInstance();
         Method m = c.getDeclaredMethod("parseXML", new Class[]{s});
         m.invoke(obj,new Object[]{xmlFileName});

   }

Working with XMLBeans in Java EE applications

You also can use the class loading mechanism when the application using XMLBeans is a Java EE application. Because most of the application servers have their own class loading hierarchy, you must ensure that the URLClassLoader instance has the class loader of the current thread context as the parent, and not the system class loader.

In this listing, the Java beans for the XSD with namespace com.ibm.sample.employee:1 have been archived into a JAR file called employee1.jar, and the Java beans for the XSD with namespace com.ibm.sample.employee:2 have been archived into a JAR file called employee2.jar. At run time, neither the JAR files nor the class files of the application itself are included in the classpath, as they will be loaded from within the proxy by an instance of the URLClassLoader. If these classes are available in the classpath, the parent of the URLClassLoader instance, which is the system class loader, will load them. Also, you will not be able load multiple versions of these JAR files as the classes will all be in the system class loaders namespace.

The proxy determines which version of the XML schema the input XML is using; based on that, it then creates an instance of the URLClassLoader and adds the URL of the appropriate JAR file to the classpath of the URLClassLoader. Once the proxy obtains the appropriate instance of the class loader, it uses Java reflection to invoke the corresponding method of the original application (or bean). Here, we use reflection because we have loaded the application using a class loader that is not the system class loader.

Now the employee data management application can process employee data that conforms to either of the XML schemas. Listing 6 shows the code that will use the proxy to invoke the application:


Listing 6. Modified client application
// Create an instance of the proxy instead of the employee application
EmployeeApplicationProxy app = new EmployeeApplicationProxy();
    app.parseXML(xmlFilePath);

In this example, the application remained unchanged. But in some cases, you might have to change the application as some new processing is required to process the XML data that conforms to new schema (such as address) in the sample. As a result, you need to manage two sets of application code. In such a case, you can load different versions of the applications (or portions of it) along with the Java beans of a particular version of the XSD. The advantage of this solution is that you can minimize the application changes, and easily manage the application when you have frequent schema changes. Also, it's easy to add or remove support for schema versions.


In conclusion

As you can see, even without support for multiple schemas, you can use XMLBeans for XML processing and still be able to manage schema variations. We hope you'll try this technique in your own work.



Download

DescriptionNameSizeDownload method
Source code samplex-xmlbeans-SampleApplication.zip10KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

  • IBM trial software for product evaluation: Build your next project with trial software available for download directly from developerWorks, including application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.

Discuss

About the authors

Photo of Abdul Rasid

Abdul Rasid is a System Software Engineer with IBM India Software Labs, Bangalore. He currently works on the WebSphere RFID Information Center development team.

Photo of Pallavi Nagesha Rao

Pallavi Nagesha Rao has worked in the IT industry for over eight years in a variety of roles, including the development of J2EE applications, transaction management systems (TXSeries), and information management systems. Currently, she leads the WebSphere RFID Information Center development at India Software Labs. She has also authored other developerWorks articles and Redbooks.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Java technology
ArticleID=332316
ArticleTitle=Dynamically manage XML schema variations in XMLBeans applications
publish-date=08262008
author1-email=abdul.rasid@in.ibm.com
author1-email-cc=dwxed@us.ibm.com
author2-email=npallavi@in.ibm.com
author2-email-cc=dwxed@us.ibm.com