Login | Register   
RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Using Java to Handle Custom WSDL Data Types : Page 4

What happens when neither the default WSDL type system nor the default encoding meet your application's needs? Don't worry, you can use custom data types and encoding formats in conjunction with Java to solve the problem.

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.

Jeff Hanson has more than 18 years of experience in the software industry. He has worked as senior engineer for the Windows OpenDoc port and as lead architect for the Route 66 framework at Novell. He is currently Chief Architect for eReinsure, which specializes in providing frameworks and platforms for J2EE-based reinsurance systems. Jeff has also authored numerous articles and books.
Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.