Working with XML and Java
3.12 Transparently Substituting XML Files
Problem
Your code refers to XML documents such as WSDL or XML Schema using remote addresses, but you want your code to automatically and transparently substitute a saved local copy of the remote resource. Or, you have defined a placeholder location for a WSDL, and you want to substitute a real value at runtime.
Solution
Use an XML catalog.
Discussion
An XML Catalog consists of one or more files that define a logical structure that maps a set of XML entities. XML catalogs cover two basic scenarios: mapping an external entity’s public or system identifier to a URI, and mapping one URI reference to another one.
XML catalogs are useful for a few reasons:
Disconnected access
XML catalogs allow your application to continue working even if you are discon-nected from the network that defines the remote resource. If you’re using your laptop in a disconnected location and you are developing a web service that uses schemas that are back in the office, you can use an XML catalog to substitute those remote schemas for local copies. You can then continue to develop without having to change code throughout your application that points to those remote resources.
Performance
XML catalogs are also important for performance reasons. Your application can use catalogs to avoid making expensive remote calls to WSDL documents.
Software development life cycle
When moving code through development, QA, staging, and production, you may find it useful to employ XML catalogs in resolving new QA entities that map to
existing production resources, for example. Depending on how your environment is configured, XML catalogs could also be useful on large teams.
It is an SOA best practice in some situations to keep your XML schemas located in a central repository. Using XML Catalogs gives you the flex-ibility to use such an approach practically, as they add a layer of indi-rection that helps you transparently move, maintain, and scale your application components.
JAX-WS implementations are required to support XML catalogs 1.1, which is a spec-ification published by OASIS. JAX-WS support comes in the form of a processing en-gine that reads the catalog and resolves the location mappings. When the JAX-WS deployment encounters a reference to an XML file for which there is an entity mapping in the catalog, the runtime substitutes the reference name for the mapped name. Put another way, the engine receives as input, such as a remote URL for a WSDL document that your application code refers to; the engine checks the catalog for a mapped entry for that URL, and if it finds one, it silently substitutes the physical document that is the mapping target. This is generally how they are used within web services, though they can be used to map replacement text for an external entity.
Using an XML catalog within a JAX-WS deployment requires a few steps:
1. Download a local copy of the remote files you want to substitute.
2. Create the XML catalog file that maps the names of the remote resources to their local substitutes.
3. Save the file with the name jax-ws-catalog.xml.
4. Package it with your deployment artifact. If this is a WAR, place the catalog file directly in WEB-INF. If this is an EAR, place it directly in META-INF.
You can read the XML Catalog specification at http://www.oasis-open .org/committees/download.php/14809/xml-catalogs.html. It is not very long.
XML catalog entities
XML catalogs are application independent and vendor independent. They are not Java-specific, but they are defined for use in any platform.
Don’t map the same entry to different resources. The first one the engine finds will always be the one it uses.
Here is an example. Say that you have a WSDL at http://localhost:8080/soaCook bookWS/CatalogServiceSN?wsdl. You have a separate project that implements a client based on this WSDL, and you do not want your application to invoke the remote resource every time the WSDL is encountered in your client code. Define an XML catalog to map this WSDL location to a local copy of the WSDL you store with your client deployment artifact. You can first save a local copy of the WSDL (and any external schemas that it imports) to a directory named src/xml. You’ll then have your build script include the WSDL and schemas in the WEB-INF directory at deploy time.
Here I am using an example of mapping remote to local documents, but this is not the only way to use catalogs; you can also just map one XML document to another that redefines it.
The generated web service client will define annotations like this:
@WebServiceClient(name="CatalogServiceSN", targetNamespace = "http://ns.soacookbook.com",
wsdlLocation = "http://localhost:8080/soaCookbookWS/CatalogServiceSN?wsdl") public class CatalogServiceSN extends Service { ... }
So the catalog file that you’ll use will replace the WSDL file and the single schema (defining the getTitle and getTitleResponse elements) that it imports. This is shown in Example 3-15.
Example 3-15. XML Catalog using system
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="system">
<system systemId="http://localhost:8080/soaCookbookWS/CatalogServiceSN?wsdl"
uri="src/xml/CatalogServiceSN.wsdl"/>
<system systemId="http://localhost:8080/soaCookbookWS/Library.xsd"
uri="src/xml/Library.xsd"/>
</catalog>
This catalog document has a few important elements, which we’ll examine now.
The <system> element does the heavy lifting. It maps the document that is referenced by the value of its systemId attribute to the value of its uri attribute. So, in the this example, any application reference to “http://localhost:8080/soaCookbookWS/
CatalogServiceSN?wsdl” will be replaced with “src/xml/CatalogServiceSN.wsdl”.
Relative URIs defined in your catalog file are always relative to the lo-cation of the catalog file itself.
The <public> element is constructed very much like <system>. It maps a given public identifier specified by its publicId attribute with the value of its uri attribute:
<public publicId="somePublicId" uri="someUri"/>
The <uri> element maps one URI to an alternate, and does so regardless of system or public identifier resolution. It has this form:
<uri name="http://www.oasis-open.org/committees/docbook/"
uri="file:///projects/oasis/docbook/website/"/>
The root element, catalog, declares its namespace and features a prefer attribute. Valid values are either public or system. This attribute indicates which type of identifier should be preferred if both are available. Let’s look at a couple of possible scenarios. If your target document contains both a public and a system identifier, and your catalog contains only a mapping for public, and prefer=public, then the mapping for public will be used. However, if your target document contains only a system identifier, and your catalog contains only a mapping for public, and prefer=public, there is no effect.
Using XML Catalogs in wsimport
The wsimport tool defines a -catalog <filename> option that allows you to specify the path to an XML catalog file during import. This will cause the generated classes to use the catalog to resolve external entity references.
The Ant task wrapper has a corresponding attribute, shown here:
<wsimport
wsdl="${wsdl.url}"
catalog="jax-ws-catalog.xml"
destdir="${gen.classes.dir}"
sourcedestdir="${src.gen.dir}"
keep="true"
extension="false"
verbose="true" >
<binding dir="${binding.dir}" includes="${binding.file}" />
</wsimport>
See Also
Norman Walsh’s paper at https://jax-ws.dev.java.net/nonav/2.1.1/docs/catalog.html.
Summary
In this chapter, we addressed XML documents, which constitute the basic unit of ex-change in an XML-based SOA. In the previous chapter, we saw how to design and use schemas, and here we’ve extended our reach to query XML documents with XPath, read and write XML documents with StAX, and transform XML instances to and from Java objects using JAXB. We also looked at various industry and open source tools that help us process XML in many useful ways.
Beginning with the next chapter, we’ll jump into web services, and see how to write programs that act as web service clients.