Kevin Krouse XMLBeans Committer Nov. 17, 2004 Copyright 2004 BEA Systems. Licensed under the Apache...

38
Kevin Krouse XMLBeans Committer Nov. 17, 2004 Copyright 2004 BEA Systems. Licensed under the Apache License, Version 2.0 Apache XMLBeans 2: Accessing the Full Power of XML in Java

Transcript of Kevin Krouse XMLBeans Committer Nov. 17, 2004 Copyright 2004 BEA Systems. Licensed under the Apache...

Kevin Krouse

XMLBeans Committer

Nov. 17, 2004

Copyright 2004 BEA Systems. Licensed under the Apache License, Version 2.0

Apache XMLBeans 2:Accessing the Full Power of XML in Java

Agenda

XmlBeans Overview

What’s new in Version 2

What’s under development for Version 2

What’s in the future for XmlBeans

XMLBeans Overview

Take Advantage of the full power of XML in Java

Underlying XML Store allows full access to the entire XML infoset whenever needed

Generated Java Classes allow Java-friendly access to XML

100% XML Schema Support

100% XML Infoset Access

Open technology (Apache Open Source)

Target

Enterprise Standard XML Technology

Make XMLSchema easy to use

Generated Java Classes

XML APIs

XML Store

XMLBeans Quick History and Status

Originally written by BEA for use within BEA technologies and for Weblogic Platform users (Weblogic Platform 8.1)

Submitted to Apache Open Source in Sep 2003 Became a top-level project in June 2004

Continued support and commitment from BEA 6 BEA Apache committers (of 13 total committers)

Released version 1.0.3 in June 2004

A Beta release of XMLBeans Version 2 very soon

XMLBeans Runtime

XML StoreHigh Speed Parser

pars

e

load

XMLBeans Architecture

XML APIs

Validation

Reads/Updates

XML Document Instance

XML Schema

Your XMLBeans Jar

Generated ClassesGenerated

ClassesGenerated

Interfaces/Classes

exte

nd

s

XML Schema Binaries(.xsb)

XML Schema Binaries(.xsb)

XML Schema Binaries(.xsb)

schema

compile

XmlObject XmlCursor DOM

(v2)

XPath STaX XQuery

XMLBeans Compile Time

Built-in schema types

codegen

schema type system (schema object model)

schema binaries (.xsb)compiled

interfaces/classes

schema validationXML

Schema

javac

GeneratedJava

Source

Schema Compilation

XmlTypes.jar

XMLBeans Generated Classes (1)

Schema’s targetNamespace becomes package name

Global elements and types become top-level classes

Anonymous types become inner classes

Local elements and attributes become properties

Simple type properties have both Java and XML set/get

<xs:schema targetNamespace="http://openuri.org/easypo"

xmlns:po="http://openuri.org/easypo"

xmlns:xs="http://www.w3.org/2001/XMLSchema"

elementFormDefault="qualified">

<xs:element name="purchase-order">

<xs:complexType>

<xs:sequence>

<xs:element name="customer" type="po:customer"/>

<xs:element name="when" type="xs:dateTime"/>

<xs:element name="line-item" type="po:line-item"

minOccurs="0" maxOccurs="unbounded"/>

<xs:element name="shipper" type="po:shipper" />

</xs:sequence>

</xs:complexType>

</xs:element>

XMLBeans Generated Classes (2)

First, the global element(s), and local elements …

Java Package: org.openuri.easypo

interface PurchaseOrderDocument extends XmlObject

interface PurchaseOrder extends XmlObject

Customer getCustomer()setCustomer(Customer)

Calendar getWhen()setWhen(Calendar)

LineItem[] getLineItemArray()addNewLineItem(LineItem)

Shipper getShipper()setShipper(Shipper)

synthetic type

XMLBeans Generated Classes (3)

<xs:complexType name="line-item">

<xs:sequence>

<xs:element name="description" type="xs:string"/>

<xs:element name="per-unit-ounces" type="xs:decimal"/>

<xs:element name="price" type="xs:double"/>

<xs:element name="quantity" type="xs:int"/>

</xs:sequence>

</xs:complexType>

<xs:complexType name="shipper">

<xs:sequence>

<xs:element name="name" type="xs:string"/>

<xs:element name="per-ounce-rate" type="xs:decimal"/>

</xs:sequence>

</xs:complexType><xs:complexType name="customer"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="phone"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="\d\d\d-\d\d\d\d"/> </xs:restriction> </xs:simpleType> </xs:element> </xs:sequence></xs:complexType>

Next, we have the ‘named’ types:

interface CustomerString getName()setName(String)

String getPhone()setPhone (String)

Phone xgetPhone()xsetPhone(Phone)

interface ShipperString getName()setName(String)

BigDecimal getPerUnitOunces()setPerUnitOunces (BigDecimal)

interface LineItemString getDescription()setDescription(String)

BigDecimal getPerUnitOunces()setPerUnitOunces (BigDecimal)

double getPrice()setPrice(double)

int getQuantity()setQuantity(int)

interface Phone

XMLBeans Generated methods

Multiple Occurrence Methods:

LineItem[] getLineItemArray()void setLineItemArray(LineItem[] MyLineItems)

Array getter, setter

Get, set, insert, remove specific itemLineItem getLineItemArray(int index)void setLineItemArray(LineItem newLineItem, int index)void insertLineItem(int index, LineItem newLineItem)void removeLineItem(int index)

maxOccurs > 0

If simple type, then “x” version methods also gennedXmlString[] xgetPhoneArray()void xsetPhoneArray(XmlString[] phonesArray)XmlString xgetPhoneArray(int index)void xsetPhoneArray(int index, XmlString newPhone)XmlString insertNewPhone(int index)void addNewPhone(XmlString newPhone)

Adding new item to endvoid addLineItem(LineItem newLineItem)

Is item nil?boolean isNilLineItemArray(int index)void setNilLineItemArray(int index)

XMLBeans Type Hierarchy

XMLBeans Java Types hierarchy match XML Schema types

Built-in Types as well as User Defined Types derive from XmlObject.Just like java.lang.Object

Built-in Types are mapped to both Xml Type oriented classes and natural java classes

Xml Type oriented classes respect XML Schema rules (e.g., cannot assign negative integer to XmlPositiveInteger)

Valid assignments to corresponding java classes can be verified using validate()

A different way to work with XML A location in an XML Instance not a Node

Lighter weight than Node based model

Fewer Objects = Less Memory, Less Garbage Collection

Access to full XML infoset (comments, PIs, whitespace)

Programming model is different than many are used to

Think of moving a cursor through a text document <PurchaseOrder><Customer>Dave</Customer></PurchaseOrder>

XmlCursor’s programming model is token based (similar to StAX)

You can work at the character level if needed.

XmlCursor, the whys and wherefores

<?xml version=“1.0” encoding=“UTF-8” ?><!-- Order summary --><?xml-stylesheet type=“text/xsl” href=“order.xslt”?><WidgetOrder batchId=“3DJ” xmlns=“org.shipping”> <Order id=“12”> <item><name>Some Widget</name></item> </Order></WidgetOrder>

Understanding XML Tokens

9 Token Types• STARTDOC• ENDDOC• START• END• TEXT• ATTR• NAMESPACE• COMMENT• PROCINST

XMLStore Architecture

XML Instance

File

Stream

String

Etc.

XML Store

Tree

Character Buffer

<purchaseOrder>

<customer>

Etc.<lastName>

Parser

Load

XmlObject XmlCursor

XML Instance

File

Stream

String

Etc.

Save

User Code

myCursor.toFirstChild();myCursor.toChild(0);myCursor.toNextToken()myCursor.toParent();myCursor.toStartDoc();myCursor.toNextSibling();myCursor.toNextChar();myCursor.toNextAttribute();myCursor.toLastAttribute();

Using XmlCursor to navigate/read

Create an XmlCursor by calling newCursor method on XmlObjectXmlCursor myCursor = XmlObject.Factory.Parse(myXmlFile).newCursor();

There are many methods for moving around the XML

instance using XmlCursor

<xq:employees xmlns:xq="http://openuri.org/selectPath">

<xq:employee>

<xq:name>Fred Jones</xq:name>

<xq:address location="home">

<xq:street>900 Aurora Ave.</xq:street>

<xq:city>Seattle</xq:city>

<xq:state>WA</xq:state>

<xq:zip>98115</xq:zip>

</xq:address>

<xq:address location="work">

<xq:street>2011 152nd Avenue NE</xq:street>

<xq:city>Redmond</xq:city>

<xq:state>WA</xq:state>

<xq:zip>98052</xq:zip>

</xq:address>

<xq:phone location="work">(425)555-5665</xq:phone>

<xq:phone location="home">(206)555-5555</xq:phone>

<xq:phone location="mobile">(206)555-4321</xq:phone>

</xq:employee>

</xq:employees>

Using XmlCursor to add an element

XmlObject newXml = XmlObject.Factory.newInstance();

First, create empty document

Create cursor and bump past the STARTDOC tokenXmlCursor cursor = newXml.newCursor();cursor.toNextToken();

Create new element using beginElement()

cursor.beginElement("item", "http://openuri.org/");

Insert an “id” attribute with a value

cursor.insertAttributeWithValue("id", "4056404");

Insert “bicycle” as an element valuecursor.insertChars("bicycle");

<ns1:item id="4056404" xmlns:ns1="http://openuri.org/">bicycle</ns1:item>

Using XPath from XmlCursor

xmlCursor.selectPath(myXPathExpression)<xq:employees xmlns:xq="http://openuri.org/selectPath">

<xq:employee>

<xq:name>Fred Jones</xq:name>

<xq:address location="home">

<xq:street>900 Aurora Ave.</xq:street>

<xq:city>Seattle</xq:city>

<xq:state>WA</xq:state>

<xq:zip>98115</xq:zip>

</xq:address>

<xq:address location="work">

<xq:street>2011 152nd Avenue NE</xq:street>

<xq:city>Redmond</xq:city>

<xq:state>WA</xq:state>

<xq:zip>98052</xq:zip>

</xq:address>

<xq:phone location="work">(425)555-5665</xq:phone>

<xq:phone location="home">(206)555-5555</xq:phone>

<xq:phone location="mobile">(206)555-4321</xq:phone>

</xq:employee>

</xq:employees>

Iterate thru selections using xmlCursor.toNextSelection()

String queryExpression =

"declare namespace xq='http://openuri.org/selectPath'" +

"$this/xq:employees/xq:employee/xq:phone”

xmlCursor.selectPath(queryExpression)

For example:

while (xmlCursor.toNextSelection())

{

System.out.println(cursor.getTextValue());

}

Code to loop through selections:

(425)555-5665

1

1

2

(206)555-55552

3

(206)555-43213

public void tryPushPop(XmlObject xml)

{

XmlCursor cursor = xml.newCursor();

cursor.toFirstChild();

cursor.push();

cursor.toChild(2);

cursor.toNextSibling();

cursor.pop();

}

Using Stored Cursor Locations with push() and pop()

|<employee>

<name>Gladys Kravitz</name>

<address location="home">

<street>1313 Mockingbird Lane</street>

<city>Seattle</city>

<state>WA</state>

<zip>98115</zip>

</address>

<address location="work">

<street>2011 152nd Avenue NE</street>

<city>Redmond</city>

<state>WA</state>

<zip>98052</zip>

</address>

<phone location="work">(425) 555-6897</phone>

<phone location="home">(206) 555-6594</phone>

<phone location="mobile">(206) 555-7894</phone>

</employee>

Agenda

XmlBeans Overview

What’s new in Version 2

What’s under development for Version 2

What’s in the future for XmlBeans

New in XMLBeans Version 2

Extensions to generated code: Interface extensions

Pre/Post events for setters

New, improved XML store Perf enhancements, synchronization on/off modes

Native live DOM – modifications are in sync with XmlCursor, XmlObject

Error Codes New, improved Compiler API

Incremental compilation

New tools: inst2xsd and xsd2inst Binary metadata partitioning Many bug fixes and improvements…

Interface Extensions in Generated Code

“Can I extend a generated XMLBean class to add methods?” Don’t do it! You’ll be sorry!

How can I add methods to a generated XMLBean? The XMLBeans schema compiler can be configured to gen code

that implements a user provided interface.

The generated XMLBean interfaces and *Impl classes will implement the interface

The implementation will call static methods on a user provided handler class.

Interface Extensions: Example

<xb:config xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config"> <xb:extension for=“generated.PurchaseOrder generated.Shipper"> <xb:interface name=“com.example.FooInterface"> <xb:staticHandler>com.example.FooHandler</xb:staticHandler> </xb:interface> </xb:extension></xb:config>

Create an .xsdconfig file Name the generated classes theextension applies to

Provide an interface

public interface FooInterface{ String doMagic(int i);}

Provide a static implementation

public class FooHandler { public static String doMagic(XmlObject o, int i) { … }}

Interface Extensions: Example Cont.

public interface PurchaseOrder extends XmlObject, FooInterface{ …}

Generated PurchaseOrder interface implements FooInterface:

public interface FooInterface { String doMagic(int i);}

public class PurchaseOrderImpl extends XmlComplexContentImpl implements PurchaseOrder{ public String doMagic(int i) { return FooHandler.doMagic(this, i); } ...}

Generated PurchaseOrderImpl implements FooInterfaceby delegating to the FooHandler static methods

public class FooHandler { public static String doMagic(XmlObject o, int i) { … }}

Pre/Post Events for Setters

“Can I extend a generated XMLBean class and override methods?” Don’t do it! You’ll be sorry!

How can I override methods of a generated XMLBean? You can’t override, but…

The XMLBeans schema compiler can be configured to gen code that calls a preSet() and postSet() handler.

Pre/Post events are only for the .setXxx(), .insertXxx(), and .removeXxx() methods.

Pre/Post Events: Example

<xb:config xmlns:xb="http://xml.apache.org/xmlbeans/2004/02/xbean/config"> <xb:extension for=“generated.PurchaseOrder generated.Shipper"> <xb:prePostSet> <xb:staticHandler>com.example.SetterHandler</xb:staticHandler> </xb:prePostSet> </xb:extension>

Create an .xsdconfig file Name the generated classes theextension applies to

public class SetterHandler{ public static boolean preSet(int opType, XmlObject xo, QName prop, boolean isAttr, int index)

public static void postSet(int opType, XmlObject xo QName prop, boolean isAttr, int index)}

Handler class with preSet/postSet methodsopType is SET, INSERT, or REMOVE

XmlObject parameter is ‘this’

QName of the property being set

isAttr is true for attribute properties

The array index of the element or -1

preSet returns true, set continues

Pre/Post Events: Example Cont.

public class PurchaseOrderImpl extends XmlComplexContentImpl { private static final QName NAME$0 = new QName(“”, “name”);

public void setName(generated.NameType name) { if (com.example.SetterHandler.preSet(PrePostExtension.SET, this, NAME$0, false, -1))) { /* XmlBeans code to set the ‘name’ element */ } com.example.SetterHandler.postSet(PrePostExtension.SET, this, NAME$0, false, -1); }

Generated PurchaseOrderImpl calls pre/post handlers

public class SetterHandler {

public static boolean preSet(int opType, XmlObject xo, QName prop, boolean isAttr, int index) { return false; }

public static void postSet(int opType, XmlObject xo, QName prop, boolean isAttr, int index) { /* do nothing */ }

Handler below will make a ‘read-only’ XmlBean

New, improved XML Store

Performance in the store very important to us. Entire XML infoset loaded in store with a binding on top requires overhead

versus shredding the xml to stuff into a POJO

Performance improvements in v2 Fewer objects (interior elements took 2 objects in v1, take one object in v2)

Less char copying and less wasted char buffer space

Preserve user’s String values for attributes/elements

Optional thread safety – turn synchronization off

Simpler architecture – v1 used a splay tree

Native DOM level 2 implementation inside the store. Now you have three views of the underlying xml: XmlObject (strongly typed schema access)

XmlCursor (cursor/token model)

DOM level 2 (tree model)

Move between all three views seamlessly

New, improved Compiler API

Refactoring to make calling the schema compiler easier XmlBeans.compileXmlBeans(…)

Parses the XMLSchema input files, compiles into a SchemaTypeSystem, generates the XmlBeans binding java code

Caller still needs to run javac on the generated files

Incremental compilation Pass in the previously compiled SchemaTypeSystem

Interpreted as a diff against list of input schemas

Every namespace from previous compilation not found in current compilation is considered unchanged – moved to the new SchemaTypeSystem

Modified components are added to new STS

Error Codes

Programmatically get error codes from compilation, parsing, or validation.

Conforms to the XMLSchema spec, Appendix C error codes Error codes like “cvc-complex-type.2.2” are interpreted as

http://www.w3c.org/TR/xmlschema-1/#cvc-complex-type clause 2.2

Some fudge factor involved, not all errors have a clause or more than one error is possible in a clause.

Most all error/warning messages have been internationalized

List list = new ArrayList();XmlOptions opts = new XmlOptions().setErrorListener(list);XmlObject xobj = XmlObject.Factory.parse(myfile, opts);if (list.size() > 0) { XmlError err = ((XmlError)list.get(0); System.out.println(“err: “ +err.getErrorCode() + “: “ + err.getMessage());}

inst2xsd tool

Creating an new XMLSchema can be a burden.

If you have a handful of XML instances, you can create an XMLSchema from them using the instance 2 schema tool

Supports three schema design patterns: Russian-Doll (local elements and local types)

Salami Slice (element refs to global elements)

Venetian Blind (local elements and global complex types)

Supports the most narrow type applicable (ints, dates, etc)

Supports enumerations for repeated values

xsd2inst tool

Given a schema and a global element, xsd2inst will generate a sample xml document

The instance will contain values for simple types

Not all possible content models will be produced

Good for a interactive editing and testing of schema and web services

Binary Metadata partitioning

Warning: advanced feature of XMLBeans

What if you have two versions of a compiled XmlBean jar on the same classpath?

Geronimo and Beehive both use XmlBeans for editing deployment descriptors

Meta-data will conflict if they are in the same namespace:

When loading metadata about the “namespace:application” element, the “/schema/element/namespace/application.xsb” resource is read from the classpath

Solution to protect against classpath conflicts?

Classloaders. But Geronimo will probably want to put XmlBeans and the compiled descriptor jar on the system classpath. It’s easier.

Add another “package” directory to the resource lookup:

/schema/org.apache.geronimo/element/namespace/application.xsb

/schema/org.apache.beehive/element/namespace/application.xsb

Lots of bug fixes

Lots of bug fixes and improvements Better wildcard support

XmlObject[] XmlObject.selectChildren(QNameSet)

PurchaseOrder.type.qnameSetForWildcardElements()

Validation optimization

xsd:annotation support is new

Redefines completely rewritten

Substitution Groups works but better support in progress

Agenda

XmlBeans Overview

What’s new in Version 2

What’s under development for Version 2

What’s in the future for XmlBeans

Current development for Version 2

XMLStore optimizations for fast XQuery execution

Binding improvements Use JDK1.5 enumerations and generics in generated code

Better support for Substitution Groups

More performance work

Agenda

XmlBeans Overview

What’s new in Version 2

What’s under development for Version 2

What’s in the future for XmlBeans

In the Future

Streaming XmlBeans with schema type information A cursor-like model with ability to do typed operations such as

“skip until next PurchaseOrder”

Solves XML store loading entire documents in-memory

Binding improvements: Collections instead of strongly typed arrays

Binding API so multiple bindings can be used for a type system

e.g., XmlBeans, JAX-RPC, SDO, JAXB2, lossy POJOs

Incremental compilation (at the type level) a schema type system that can be incrementally built

great for an IDE/schema editor

Questions/Comments

“When you need to use XML and XMLSchema in Java, XMLBeans is the best!”

-- Ted Leung, from ApacheCon 2004 XML talk (Nov., 16th)

Any questions?

Site: http://xmlbeans.apache.org/ Wiki: http://wiki.apache.org/xmlbeans Email lists:

[email protected]

[email protected]

Slides:

http://www.apache.org/~kkrouse/apachecon/ac2004_XmlBeans_v2.ppt