Building Custom WSDL Interpreters with XMLBeans
The WSDL2Java class below is an example of a simple WSDL-to-Java interpreter using XMLBeans. You can
download all the source code for this article to follow along.
package com.jeffhanson.clienttier;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.impl.xb.xsdschema.*;
import org.apache.xmlbeans.impl.xb.xsdschema.impl.*;
import org.apache.xmlbeans.impl.xb.substwsdl.*;
import org.apache.xmlbeans.impl.util.FilerImpl;
import
org.apache.xmlbeans.impl.schema.SchemaTypeSystemCompiler;
import
org.apache.xmlbeans.impl.schema.SchemaTypeLoaderImpl;
import org.apache.xmlbeans.impl.schema.StscState;
import org.apache.xmlbeans.impl.common.XmlErrorWatcher;
import org.apache.xmlbeans.impl.common.IOUtil;
import java.util.*;
import java.io.File;
import repackage.Repackager;
public class WSDL2Java
{
private static class MyResolver
implements org.xml.sax.EntityResolver
{
public
org.xml.sax.InputSource resolveEntity(
String publicId,
String systemId)
{
System.out.println("System ID: " + systemId);
return null;
}
}
...
The
generate method shown in
Listing 2 parses a given WSDL file and generates Java code representing the data types found in the
<Types> section of the WSDL document.
The
compileSchemas method creates the XMLBeans-specific schema files (
.xsb's) and saves them to disk.
private SchemaTypeSystem compileSchemas(
String schemaFilesDir, ArrayList scontentlist,
MyResolver entityResolver,
XmlErrorWatcher errorListener)
{
SchemaDocument.Schema[] sdocs =
(SchemaDocument.Schema[])scontentlist.toArray(
new SchemaDocument.Schema[scontentlist.size()]);
ResourceLoader cpResourceLoader = null;
SchemaTypeLoader linkTo =
SchemaTypeLoaderImpl.build(null,
cpResourceLoader, null);
File baseDir = new File(System.getProperty(
"user.dir"));
java.net.URI baseURI = baseDir.toURI();
XmlOptions opts = new XmlOptions();
opts.setCompileNoValidation();
opts.setEntityResolver(entityResolver);
Map sourcesToCopyMap = new HashMap();
File schemasDir = IOUtil.createDir(new File("."),
schemaFilesDir);
// create parameters for the main compile function
SchemaTypeSystemCompiler.Parameters params =
new SchemaTypeSystemCompiler.Parameters();
params.setName(null);
params.setSchemas(sdocs);
params.setLinkTo(linkTo);
params.setOptions(opts);
params.setErrorListener(errorListener);
params.setJavaize(true);
params.setBaseURI(baseURI);
params.setSourcesToCopyMap(sourcesToCopyMap);
params.setSchemasDir(schemasDir);
System.out.println("Compiling schemas...");
try
{
// create schema files (.xsb's)
SchemaTypeSystem sts =
SchemaTypeSystemCompiler.compile(params);
// now save .xsb's to disk
sts.saveToDirectory(schemasDir);
System.out.println(
"Schema compilation succeeded");
return sts;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
The
generateJavaSource method generates Java source files for the WSDL data types that have previously been added to a given type system.
private List generateJavaSource(String schemaClassesDir,
String schemaSrcDir, SchemaTypeSystem sts)
{
File classesDir = new File(schemaClassesDir);
File srcDir = IOUtil.createDir(new File("."),
schemaSrcDir);
// now, generate the source files
XmlOptions options = new XmlOptions();
boolean verbose = false;
boolean incrSrcGen = false;
Repackager repackager = null;
FilerImpl filer = new FilerImpl(classesDir,
srcDir, repackager, verbose, incrSrcGen);
System.out.println("Generating Java source...");
if (SchemaTypeSystemCompiler.generateTypes(sts,
filer, options))
{
System.out.println(
"Java source generation succeeded");
return filer.getSourceFiles();
}
else
{
System.out.println("Java source generation failed");
}
return null;
}
The
addWsdlSchemas method shown in
Listing 3 extracts the
<Types> array from a WSDL definition document and adds the schemas representing each type to the content list.
The JavaSourceCompiler class uses utilities from the XMLBeans API to compile previously generated Java source files:
package com.jeffhanson.clienttier;
import org.apache.xmlbeans.impl.tool.CodeGenUtil;
import org.apache.xmlbeans.impl.common.IOUtil;
import java.io.File;
import java.util.List;
public class JavaSourceCompiler
{
public JavaSourceCompiler()
{
}
public void generate(String schemasDirName,
List sourceFiles,
String classesDirName)
{
File classesDir = new File(classesDirName);
File schemasDir = IOUtil.createDir(new File("."),
schemasDirName);
boolean verbose = false;
// now, compile source files
String compiler =
"/tools/VMs/j2sdk1.4.2_04/bin/javac.exe";
File[] tempClasspath = CodeGenUtil.systemClasspath();
File[] classpath = new
File[tempClasspath.length + 1];
System.arraycopy(tempClasspath, 0, classpath, 0,
tempClasspath.length);
classpath[tempClasspath.length] = schemasDir;
boolean debug = false;
String javasource = null;
String memoryInitialSize =
CodeGenUtil.DEFAULT_MEM_START;
String memoryMaximumSize =
CodeGenUtil.DEFAULT_MEM_MAX;
boolean quiet = true;
System.out.println("Compiling Java source files...");
if (CodeGenUtil.externalCompile(
sourceFiles, classesDir,
classpath, debug, compiler, javasource,
memoryInitialSize, memoryMaximumSize,
quiet, verbose))
{
System.out.println("Source compile succeeded");
}
else
{
System.out.println("Source compile failed");
}
}
}
I urge you to
download the source code for this article and experiment with it yourself.
Web services messaging and XML-based data transfer has created a need to for a structured way to express message exchanges. The Web services Description Language (WSDL) deals with this need by defining an XML-based service description and generic data-type system for any programming language.
The WSDL data-
type system defines data types that can be exchanged between service consumers and providers. WSDL allows you to use the built-in XML-Schema simple types, or you can define your own custom types.
The Streaming API for XML (StAX) specification defines a new API using a bi-directional API for parsing and streaming XML. StAX allows you to maintain parsing control by exposing a simple iterator-based API, as well as a cursor API. The iterator-based API lets you "pull" events as needed. The cursor API facilitates processing-control even further by letting you stop processing, skip ahead to sections of a document, and retrieve subsections of a document.
Apache XMLBeans (originated by BEA and then donated to Apache) is an open source, XML-Java binding tool based on the StAX specification that can be used to generate Java classes and interfaces from an XML schema. These classes and interfaces can then be used to parse or generate XML documents that conform to the schema.
The combination of StAX and the XMLBeans framework allows developers to dynamically interpret and operate on WSDL documents and the data-types declared therein with a greater degree of power and flexibility than standard static XML-parsing and processing techniques.