Jun Qian (钱骏) 's Weblog |
|
Tuesday Jul 22, 2008
XAM AutoGen: a tool to automate XAM model generation
XAM (Extensible Abstract Model) is an extensible framework for building domain-specific object model on top of any base models. Many NetBeans modules (such as WSDL Model, Schema Model, XSLT Model, BPEL Model) are built on top of XAM. A XAM-based model is best suited for an IDE like NetBeans because of its IDE-friendly features (unlimited undo/redo, automatic synchronization, document fidelity, etc.), but you are not tied to NetBeans by using XAM.
To create a XAM-based model, one typically starts from the schema describing the domain. It's a very tedious process to generate all the Java interfaces and implementation classes, along with the all plumbing classes (factories, visitors, etc.). To ease the pain of manual class creation, a tool is needed to auto generate a XAM-based model from a XML schema. This blog entry describes a tool that takes a domain schema as input, and uses Velocity templates to generate a XAM-based model. This tool doesn't use any popular schema language (such as XML Schema (W3C), or Relax NG.) There are a couple of reasons:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xml.netbeans.org/schema/xamgen" xmlns:tns="http://xml.netbeans.org/schema/xamgen" elementFormDefault="qualified"> <xsd:element name="Content"> <xsd:complexType> <xsd:sequence> <xsd:element name="Element" minOccurs="0" maxOccurs="unbounded"/> <xsd:element name="EnumType" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="Element"> <xsd:complexType> <xsd:sequence> <xsd:element name="Attribute" minOccurs="0" maxOccurs="unbounded"/> <xsd:element name="ChildElement" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="className" type="xsd:string"/> <xsd:attribute name="root" type="xsd:boolean" default="false"/> <xsd:attribute name="virtual" type="xsd:boolean" default="false"/> <xsd:attribute name="base" type="xsd:string"/> <xsd:attribute name="anyAttribute" type="xsd:boolean" default="false"/> <xsd:attribute name="anyElement" type="xsd:boolean" default="false"/> </xsd:complexType> </xsd:element> <xsd:element name="Attribute"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="type" type="xsd:string" use="required"/> <xsd:attribute name="reference" type="xsd:string"/> </xsd:complexType> </xsd:element> <xsd:element name="ChildElement"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string" use="required"/> <xsd:attribute name="multiplicity" type="xsd:string" default="n"/> <xsd:attribute name="ordered" type="xsd:boolean" default="false"/> </xsd:complexType> </xsd:element> <xsd:element name="EnumType"> <xsd:complexType> <xsd:sequence> <xsd:element name="Enumeration" minOccurs="0" maxOccurs="unbounded"/> </xsd:sequence> </xsd:complexType> </xsd:element> <xsd:element name="Enumeration"> <xsd:complexType> <xsd:attribute name="value" type="xsd:string" use="required"/> </xsd:complexType> </xsd:element> </xsd:schema> Most of it should be pretty straightforward. Here are a few notes:
Example: Here is a schema instance describing an example domain: <Content xmlns="http://xml.netbeans.org/schema/xamgen" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xml.netbeans.org/schema/xamgen xamgen.xsd"> <Element name="composite" root="true"> <Attribute name="name" type="String"/> <Attribute name="targetNamespace" type="java.net.URI"/> <ChildElement name="component"/> <ChildElement name="connection"/> </Element> <Element name="component"> <Attribute name="name" type="String"/> <ChildElement name="provides"/> <ChildElement name="consumes"/> <ChildElement name="property"/> </Element> <Element name="endpoint" virtual="true"> <Attribute name="name" type="String"/> <ChildElement name="interface" multiplicity="1"/> </Element> <Element name="provides" base="endpoint"/> <Element name="consumes" base="endpoint"/> <Element name="property"> <Attribute name="name" type="String"/> <Attribute name="value" type="String"/> <Attribute name="override" type="OverrideOptions"/> </Element> <Element name="connection"> <Attribute name="source" type="javax.xml.namespace.QName" reference="consumes"/> <Attribute name="target" type="javax.xml.namespace.QName" reference="provides"/> </Element> <Element name="interface" virtual="true"/> <Element name="interface.wsdl" className="InterfaceWSDL" base="interface"> <Attribute name="interface" type="java.net.URI"/> </Element> <EnumType name="OverrideOptions"> <Enumeration value="no"/> <Enumeration value="may"/> <Enumeration value="must"/> </EnumType> </Content> Here is a little configuration file: # XML file describing the domain data model. The following shows the list of classes this XAM AutoGen Tool spits out when fed with the above domain schema and configuration file: Usage: Here is the steps you need to take to use this tool:
That's it. I am currently using this tool to auto generate the data model for SCA (Service Component Architecture). Here is the domain schema for the SCA Assembly Model. You can compare it with the original XSD Schemas. Based on my usage, I am going to keep improving this XAM AutoGen Tool . If you have any comments or suggestions, I am all ears.
P.S. I found this NetBeans Velocity plugin along the way. Very nice as a Velocity template viewer, but once you start editing the templates, it's getting a little crazy sometimes. Posted at 03:01AM Jul 22, 2008 by Jun Qian in NetBeans | Comments[3] |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
I'm wondering if the XAM models and your generator can be used on stuff that is not completely described by xsd, such as the apache maven's pom.xml (http://maven.apache.org/xsd/maven-4.0.0.xsd)
elements under <configuration> are not defined and are specific to the maven plugin being used.
Posted by Milos Kleint on July 22, 2008 at 05:04 AM PDT #
Sure. The tool generates a class called xxxExtensibilityElementBase under model.spi which you can extend to define any extensibility elements not defined in your domain. You then need to define an ElementFactory for your extensibility elements and register it using META-INF/Services. I will consider adding this feature into a future version. Thanks!
Posted by Jun Qian on July 22, 2008 at 12:13 PM PDT #
The zip file in the original post has been updated for a bug fix.
Posted by Jun Qian on July 22, 2008 at 12:59 PM PDT #