by Bea Chan
When integrating legacy applications or integration systems with BEA WebLogic Workshop you frequently rely on XML and schemas. However, some legacy systems were not originally designed to handle XML namespaces. Instead, these legacy systems only accept plain XML messages without target namespaces, and this can create conflicts in WebLogic Workshop. Indeed, global types or elements with the same name may be defined in multiple schemas.
This article describes how WebLogic Workshop and XMLBeans can help address this problem in a powerful and elegant way. The article assumes you have basic knowledge of XML schemas and XMLBeans. You can download the examples used in this article.
XMLBeans provides a way to handle XML by manipulating Java classes that represent the XML. The classes are created using a schema to which the XML conforms. You can use XMLBeans to compile one or multiple schema files to generate Java types.
A common problem encountered when integrating legacy solutions is working with multiple schemas from different sources, each without a specified target namespace. If these schemas share element names, WebLogic Workshop schema projects are unable to successfully compile the generated Java types, and errors such as "Duplicate global type" or "Duplicate global element" appear. A scenario is illustrated as below:
Assume you use WebLogic Workshop and you create a new application. Typically you create a schema project, import your schema, and WebLogic Workshop automatically compiles it into XMLBeans:
<xs:schema xmlns:po="http://openuri.org/easypo" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="purchase-order" type="customer"/> <xs:complexType name="customer"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="address" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:schema>
Listing 1: Schema1.xsd
Schema1, with no target namespace, gives the following XML document with element name
<?xml version="1.0" encoding="UTF-8"?> <purchase-order xmlns:po="http://openuri.org/easypo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" > <name>John</name> <address>123 North First St</address> </purchase-order>
Listing 2: Sample1.xml
If you try generating Java types from this schema you'll see that the schema is properly compiled into an XMLBean. Now you can import another schema:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:foo="http://openuri.org/clientdb" elementFormDefault="qualified"> <xs:element name="client-record" type="customer"/> <xs:complexType name="customer"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="address" type="xs:string"/> <xs:element name="phone" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:element name="purchase-order" type="customer"/> </xs:schema>
Listing 3: Schema2.xsd
Schema2 doesn't have a target namespace either. The following XML document is an instance of this schema, with element name
<?xml version="1.0" encoding="UTF-8"?> <client-record xmlns:foo="http://openuri.org/clientdb" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <name>Susan</name> <address>6789 South Second St</address> <phone>408-123-4567</phone> </client-record>
Listing 4: Sample2.xml
When these two schema files are imported into a schema project in WebLogic Workshop and XMLBeans classes are generated, WebLogic Workshop is going to display compilation errors:
ERROR: error: Duplicate global type: customer
ERROR: error: Duplicate global element: purchase-order
As you can see the compiler complains that the global type
customer and the global element
purchase-order are defined multiple times. This is not very surprising when you look at our schema. Conflicts such as this are likely to happen when schemas have no target namespace. I'll now show how you can address this problem.
You can choose from a number of possible solutions to this problem. I'll discuss three solutions here.
Adding different target namespaces to your schemas would solve the problem—and this is the recommended approach. Unfortunately, most of the time you have no control over the schemas and you need to find another way.
Another approach to solving the problem is to create two schema projects in WebLogic Workshop. In this example, assume you create another Schema project in your application and compile schema1.xsd and schema2.xsd respectively in schema project1 and schema project2, as shown in Figure 1.
In this case the schemas will compile successfully. Each project will not complain about duplicate definitions. However, take a look at the generated classes shown in Figure 1. The
Libraries folder contains two jar files,
SchemaP2.jar, which are the result of WebLogic Workshop compilation. The
noNamespace.PurchaseOrderDocument classes are defined in both jars, as shown in this figure.
Figure 1: A WebLogic Workshop application with the two schema projects
Java classes (XMLBeans) with the same name have been created in your application; as a result, you will not be able to select which one you want to use in your application. In this case, you have the same name collision problem as before, but this time it is with the application classloader.
Observe also the Java package name "noNamespace" may not be developer-friendly and should be changed to adhere to your coding conventions. This points the way to a real solution—if you change the package name you'll avoid the conflict. These issues can be solved in the third approach.
You can read an excellent article about XMLBeans compiler options on Dev2Dev. See Configuring XMLBeans by Hetal Shah (Dev2Dev, November 2004). As the article illustrates, when running the XMLBeans compiler you can specify an optional configuration file that modifies the behavior of the XMLBeans generator. In this case, name collisions and unfriendly package names can be addressed.
You can create a
compiler1.xsdconfig file in the schema "project1" as shown in Figure 2. You will get an error:
ERROR: compiler1.xsdconfig:0: Document D:\SP5\user_projects\domains\Dev2Dev\SchemaP1\compiler1.xsdconfig is not an xsd config file
You can safely ignore the above error, since the created file is empty and invalid for now. You are going to use the configuration file to specify the Java package name used to generate XMLBeans for XML elements and types defined with no target namespace. The trick is to use the reserve words
"##local" as follows:
<xb:config xmlns:xb="http://www.bea.com/2002/09/xbean/config"> <!-- Use the "namespace" element to map a namespace to the Java package name that should be generated. --> <xb:namespace uri="##local"> <xb:package>com.foo</xb:package> </xb:namespace> </xb:config>
Listing 5: compiler1.xsdconfig
Now if you go to the
Libraries folder you will see the schema "Project1" jar contains classes in the Java package
com.foo instead of
noNamespace as in Figure 1. Obviously you should use valid Java package names, otherwise you'll generate errors.
Figure 2: Location of xsdconfig.xml within the WebLogic Workshop project, and the resulting jars
Now you can perform the same steps on Project2 by creating a similar
Legacy XML applications sometimes omit namespaces, and this can cause an integration headache. This article shows how to relieve the pain by compiling your schema with an XMLBeans configuration file. This XMLBeans configuration file lets you control how names are chosen for the generated types. The configuration file is designed to map schema type names to generated Java type names. This same approach can prevent similar issues from arising when schemas have identical namespaces.
Download the sample schema, xsdconfig, and XML files for this article: schemaex.zip
Bea Chan is a Senior Developer Relations Engineer with BEA. Beaky is a Sun Certified Java Programmer.