5

Looking for a way to define a base XML schema to be re-used on additional schemas as XML messages that will be used for different JMS message payloads. The intent is to:

  • XmlMessage - Define a base Message class that all messages will be sent as.
  • Header - class that all messages will have containing meta data about the message
  • Body - abstract class that each specific message implementation can use to define the messagee payolad of each individual message

This approach will:

  • Allow the JMS EJB to unmarshal incoming XML into the high level generic XmlMessage and then be able to evaluate the class type of the Body implementation to determine how to handle the message.
  • Standardize the various message formats.
  • Take advantage of JAXB to generate the Java classes to be used on both the client sending the message and the EJB processing the message.
  • Take advantage of JAXB to marshal/unmarshal the XML in the message payload.

1 Answer 1

5

Please see the following XSD schemas and JAXB implementations to accomplish defining an abstract class for the Message’s Body

XmlMessage.xsd to define the format of all messages:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.samnunnally.com" targetNamespace="http://www.samnunnally.com" version="1.0">
<xs:element name="xmlMessage">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="header" type="header" minOccurs="1" maxOccurs="1"/>
            <xs:element ref="body"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>
<xs:complexType name="header">
    <xs:sequence>
        <xs:element name="message_class" type="xs:string"/>
        <xs:element name="message_id" type="xs:int"/>
        <xs:element name="message_length" type="xs:int"/>
        <xs:element name="software_version" type="xs:string"/>
        <xs:element name="correlation_id" type="xs:string"/>
        <xs:element name="session_id" type="xs:string"/>
        <xs:element name="return_code" type="xs:string"/>
    </xs:sequence>
</xs:complexType>
<xs:element name="body" type="body"/>
<xs:complexType name="body" abstract="true">
    <xs:sequence/>
</xs:complexType>

Example xsd implementing XmlMessage.xsd. Ends up being message Foo containing a list of customers. The key is to use substitutionGroup attribute and xs:extension base="body"

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
       xmlns="http://www.samnunnally.com" 
       targetNamespace="http://www.samnunnally.com" 
       version="1.0">
<xs:include schemaLocation="XmlMessage.xsd"/>
<xs:element name="foo" type="foo" substitutionGroup="body"/>
<xs:complexType name="foo">
    <xs:complexContent>
        <xs:extension base="body">
            <xs:sequence>
                <xs:element name="customers" type="customer" minOccurs="1" maxOccurs="unbounded"/>
            </xs:sequence>
        </xs:extension>
    </xs:complexContent>
</xs:complexType>
<xs:complexType name="customer">
    <xs:sequence>
        <xs:element name="customer_id" type="customerId" nillable="false" minOccurs="1" maxOccurs="1"/>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="street" type="xs:string"/>
        <xs:element name="city" type="xs:string"/>
        <xs:element name="state" type="xs:string"/>
        <xs:element name="zip" type="xs:string"/>
        <xs:element name="phone" type="xs:string"/>
    </xs:sequence>
</xs:complexType>
<xs:complexType name="customerId">
    <xs:sequence>
        <xs:element name="id" type="xs:string" minOccurs="1" maxOccurs="1"/>
    </xs:sequence>
</xs:complexType>

Key Java classes generated by JAXB:

Message:

package com.samnunnally;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "header",
    "body"
})
@XmlRootElement(name = "xmlMessage")
public class XmlMessage {

    @XmlElement(required = true)
    protected Header header;
    @XmlElementRef(name = "body", namespace = "http://www.samnunnally.com", type = JAXBElement.class)
    protected JAXBElement<? extends Body> body;

    public Header getHeader() {
        return header;
    }

    public void setHeader(Header value) {
        this.header = value;
    }

    public JAXBElement<? extends Body> getBody() {
        return body;
    }

    public void setBody(JAXBElement<? extends Body> value) {
        this.body = value;
    }
}

Body:

package com.samnunnally;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "body")
@XmlSeeAlso({
Foo.class
})
public abstract class Body {
}

Foo message:

package com.samnunnally;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "foo", propOrder = {
    "customers"
})
public class Foo
    extends Body
{

    @XmlElement(required = true)
    protected List<Customer> customers;

    public List<Customer> getCustomers() {
        if (customers == null) {
            customers = new ArrayList<Customer>();
        }
        return this.customers;
    }

}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.