Using the event API to publish an event to the Event Delivery Network (EDN) – the Spring way

The Event Delivery Network (EDN) in Oracle SOA Suite 11g provides a declarative way to use a publish/subscribe model to generate and consume business events without worrying about the underlying message infrastructure. Events can be published / subscribed from a variety of programming environments such as Java, PL/SQL, SOA Composites, and ADF-BC applications

In his blog Clemens showed how the Event API can be used to publish an event programmatically to the Event Delivery Network (EDN). I took the sample code Clemens provided and did some refactoring to make it more “Spring like”.

My idea is to use some of the features of the Spring Framework to simplify the publishing of Business Events to EDN from Java, without worrying about the details of the Java event API. The following features are of interest:

    The goal is to make publishing an Business Event to EDN from Java as simple as that:
// create a new customer
Customer cust = new Customer();
cust.setId(1);
cust.setFirstName("Guido");
cust.setLastName("Schmutz");

Address adr = new Address();
adr.setStreet("Papiermuehlestrasse 73");
adr.setZipCode(3014);
adr.setCity("Bern");
adr.setCountry("Switzerland");
cust.setAddress(adr);

// create a new customer event, passing the customer object as the payload
NewCustomerEvent event = new NewCustomerEvent(this, cust);

// publish the event through the Spring Event Handling mechanism
context.publishEvent(event);

    We just use simple Java objects (POJOs) to create an event and its payload and then publish it through the Spring application context as a standard Spring event.
    Sounds interesting to you? Yes, but what is needed behind the scene to make this work?
    Before we start to dig into the Java implementation, let’s first create the Business Event inside the Oracle SOA Suite 11g and implement a composite subscribing to this event.

    First, you need to define the data-shape of the event. This is done conventionally through the usage of XML Schema (File customer.xsd).

    <?xml version="1.0" encoding="windows-1252" ?>
    <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                xmlns:cus="http://www.trivadis.com/cdm/customer"
                targetNamespace="http://www.trivadis.com/cdm/customer"
                elementFormDefault="qualified">
      <xsd:element name="customer">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="id" type="xsd:integer"/>
            <xsd:element name="firstName" type="xsd:string"/>
            <xsd:element name="lastName" type="xsd:string"/>
            <xsd:element name="address">
              <xsd:complexType>
                <xsd:sequence>
                  <xsd:element name="street" type="xsd:string"/>
                  <xsd:element name="city" type="xsd:string"/>
                  <xsd:element name="zipCode" type="xsd:integer"/>
                  <xsd:element name="country" type="xsd:string"/>
                </xsd:sequence>
              </xsd:complexType>
            </xsd:element>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>
    </xsd:schema>
    
    

     

    After that the Business Event can be defined using the Event Definition Language (EDL).

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <definitions xmlns="http://schemas.oracle.com/events/edl"
                 targetNamespace="http://www.trivadis.com/events/edl/CustomerEventDefinition">
      <schema-import namespace="http://www.trivadis.com/cdm/customer"
                     location="xsd/customer.xsd"/>
      <event-definition name="NewCustomer">
        <content xmlns:ns0="http://www.trivadis.com/cdm/customer"
                 element="ns0:customer"/>
      </event-definition>
    </definitions>
    

     

    At last we can publish/subscribe to that event from a SOA Suite composite. For our example, I have defined a simple Mediator component listening on the NewCustomer event, which is then sent to a BPEL component for processing.

    tmp

       

      After deploying this SCA composite to the server, we are ready on the SOA Suite side to consume NewCustomer events. Now let’s implement the producer side in Java.

      Defining the Event in Java


      We start with the payload (the information) of the event. As shown in the Java snippet above, the goal is to pass the event payload as a normal Java object, without having to worry about the XML representation necessary for publishing the event through the API.

      The act of converting an XML document to/from an object is called Object/XML Mapping or O/X Mapping for short. There are quite a lot of Java frameworks supporting this Object/XML Mapping, like JAXB, Castor, XMLBean, JiBX or XStream. For this post I will use the JiBX framework, as it offers a flexible approach when starting with an XML Schema.

      In my previous post Using the new Object/XML Mapping Support of Spring 3.0 with JiBX and Maven I have presented how to work with JiBX from Spring using Maven as the build tool. The same approach I will use here as well.

      With the XML Schema customer.xsd used for the BusinessEvent definition above as input, the JiBX framework generates the two Java classes Customer and Address defining the payload of our event in Java.

      public class Customer
      {
          private int id;
          private String firstName;
          private String lastName;
          private Address address;
      
          // public getter and setter method not shown
      }
      
      public class Address
      {
          private String street;
          private String city;
          private int zipCode;
          private String country;
      
          // public getter and setter method not shown
      }
      
      

      Next let’s define the NewCustomerEvent class, which defines the event itself and acts as a wrapper for the event payload.

      public class NewCustomerEvent extends AbstractApplicationEventForEDN {
      
      	private Customer customer;
      	private final static String NAMESPACE = "http://www.trivadis.com/events/edl/CustomerEventDefinition";
      	private final static String NAME = "NewCustomer";
      
      	
      	public NewCustomerEvent(Object source, Customer customer) 
                                throws XmlMappingException, ParserConfigurationException, IOException {
      		super(source, NAMESPACE, NAME, customer);
      	}
      }
      
      

      The payload, customer in the case here, can be passed in the 2nd argument of the constructor. The other properties necessary for a Business Event in EDN (namespace and name) are defined as constant values, passed to the constructor of the parent class.
      NewCustomerEvent inherits from AbstractApplicationEventForEDN, the base class for all events to be published to EDN. It defines the common properties of an Business Event, like namespace, local name, content, event id and conversation id.

      public abstract class AbstractApplicationEventForEDN extends ApplicationEvent {
      
      	private String namespace;
      	private String name;
      	private Object content;
      	private Object eventId;
      	private Object conversationId;
      
      	public AbstractApplicationEventForEDN(Object source, String namespace, String name, Object content) throws ParserConfigurationException, XmlMappingException, IOException {
      		super(source);
      		
      		this.namespace = namespace;
      		this.name = name;
      		this.content = content;
      		this.eventId = UUID.randomUUID();
      		this.conversationId = UUID.randomUUID();
      	}
      
      	// setter method not shown
      }
      
      

      AbstractApplicationEventForEDN itself inherits from ApplicationEvent, a class provided by the Spring event handling mechanism. This means that such a Java Business Event is automatically a Spring ApplicationEvent so that it can be published in the Spring event handling mechanism like any other Spring event.

      So far we have a Java representation of the Business Event with its payload and we are able to publish these events through Spring.
      Next we will see how we can connect to EDN and publish the Business Events in a Spring way.

      Creating a FactoryBean to abstract away the creation of a BusinessEventConnection

      First let’s start with the link from Java to the Event Delivery Network. To talk to EDN, we need an instance of oracle.fabric.blocks.event.BusinessEventConnection. To create such an instance, the EDN Java API provides a factory interface named BusinessEventConnectionFactory together with an implementation through SAQRemoteBusinessEventConnectionFactory.
      I use such a FactoryBean to wrap the creation of a BusinessEventConnection.

      public class BusinessEventConnectionFactoryBean implements FactoryBean, InitializingBean {
      
      	DataSource dataSource;
      	BusinessEventConnectionFactory businessEventConnectionFactory;
      	
      	public void setDataSource(DataSource dataSource) {
      		this.dataSource = dataSource;
      	}
      
      	public void afterPropertiesSet() throws Exception {
              businessEventConnectionFactory = 
                  new SAQRemoteBusinessEventConnectionFactory(
                      dataSource, dataSource, null);
      	}
      
      	public Object getObject() throws Exception {
      		return businessEventConnectionFactory.createBusinessEventConnection();
      	}
      
      	public Class getObjectType() {
      		return BusinessEventConnection.class;
      	}
      
      	public boolean isSingleton() {
      		return false;
      	}
      }
      
      
      BusinessEventConnectionFactoryBean  declares a dependency to a DataSource, which is necessary for creating a BusinessEventConnectionFactory. This means that the DataSource needs to be injected through Spring, so a bean configuration is necessary in the Spring context XML definition
    <context:property-placeholder location="classpath:jdbc.properties"/>
    
    <bean id="businessEventConnection" class="com.trivadis.soa.BusinessEventConnectionFactoryBean">
    	<property name="dataSource" ref="dataSource"/>
    </bean>
    	
    <bean id="dataSource" class="oracle.jdbc.xa.client.OracleXADataSource">
    	<property name="user" value="${jdbc.username}"/>
    	<property name="password" value="${jdbc.password}"/>
    	<property name="URL" value="${jdbc.url}"/>
    	<property name="implicitCachingEnabled" value="false"/>
    </bean>
    

     

    The DB connection properties can be externalized into a properties file (jdbc.properties) by using the Spring context:property-placeholder element.

    jdbc.url=jdbc:oracle:thin:@soavm11.trivadis.com:1521:repoas
    jdbc.username=dev_soainfra
    jdbc.password=oracle
    

     

    When running in an Java EE application server, the DataSource can easily be retrieved via JNDI by switching the bean configuration as follows

    <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
        <property name="jndiName" value="jdbc/MyDataSource"/>
    </bean>
    
    

     

    With the BusinessEventConnection bean set up, let’s see how the Java event classes (i.e. NewCustomerEvent) can be published to EDN.

       

      Publishing the Event to the Event Delivery Network (EDN)

    According to Spring Best Practices we first define an interface which the event publisher implementation will need to implement. The publishEvent() method declares a parameter of type AbstractApplicationEventForEDN, so any child class extending it will be accepted and published.

    public interface BusinessEventPublisher {
    
    	public abstract void publishEvent(AbstractApplicationEventForEDN applicationEvent)
    			throws XmlMappingException, IOException;
    
    }
    

     

    My implementation of the BusinessEventPublisher can be seen below with the BusinessEventPublisherEDN class. The publishEvent() method first marshals the payload (content property) of the AbstractApplicationEventForEDN into an XML document using the Spring O/X Mapping support. The Marshaller implementation to be used is injected by Spring at initialization time (for more information see my other blog post).

    After that an instance of oracle.fabric.common.BusinessEvent is created and published via the BusinessEventConnection, which is also injected by Spring (i.e. the bean declared before).

    public class BusinessEventPublisherEDN implements BusinessEventPublisher {
    
    	private BusinessEventConnection conn;
    	private Marshaller marshaller;
    
    	public void setBusinessEventConnection(BusinessEventConnection conn) {
    		this.conn = conn;
    	}
    
    	public void setMarshaller(Marshaller marshaller) {
    		this.marshaller = marshaller;
    	}
    
    	public void publishEvent(AbstractApplicationEventForEDN applicationEvent) throws XmlMappingException, IOException {
    		DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
    				.newInstance();
    		DocumentBuilder builder = null;
    		try {
    			builder = documentBuilderFactory.newDocumentBuilder();
    		} catch (ParserConfigurationException e) {
    			e.printStackTrace();
    		}
    		Document document = builder.newDocument();
    		DOMResult result = new DOMResult(document);
    
    		marshaller.marshal(applicationEvent.getContent(), result);
    		Element payload = document.getDocumentElement();
    
    		BusinessEvent event = buildEvent(applicationEvent, payload);
    		conn.publishEvent(event, 3);
    	}
    
    	private BusinessEvent buildEvent(
    			AbstractApplicationEventForEDN applicationEvent, Element payload) {
    		BusinessEventBuilder beb = BusinessEventBuilder.newInstance();
    		QName eventName = new QName(applicationEvent.getNamespace(), applicationEvent
    				.getName());
    		beb.setEventName(eventName);
    		beb.setBody(payload);
    		beb.setProperty(BusinessEvent.EVENT_ID, applicationEvent.getEventId());
    		beb.setProperty(BusinessEvent.PROPERTY_CONVERSATION_ID, applicationEvent
    				.getConversationId());
    		beb.setProperty(BusinessEvent.PRIORITY, 1);
    		BusinessEvent be = beb.createEvent();
    		return be;
    	}
    }
    
    

     

    I could use this EventPublisher implementation directly to publish events by injecting it all the event producer beans.

    But my idea is to use the Spring event handling mechanism as the base event transport inside the Spring application and to have one common/central place where all Spring event of type AbstractApplicationEventForEDN are forwarded to Oracle EDN.

    For that I have implemented the Spring ApplicationListener using the AbstractApplicationEventForEDN base class as the type parameter. This has the effect that the listener does only subscribe to subclasses of AbstractApplicationEventForEDN, i.e. all my Java EDN events. The listener uses the injected BusinessEventPublisher instance to publish the events to EDN. This listener implementation basically acts as a bridge from the Spring event handling mechanism to the Event Delivery Network.

    public class ApplicationEventListenerEDN implements ApplicationListener<AbstractApplicationEventForEDN> {
    
    	private BusinessEventPublisher businessEventPublisher;
    	
    	public void setBusinessEventPublisher(
    			BusinessEventPublisher businessEventPublisher) {
    		this.businessEventPublisher = businessEventPublisher;
    	}
    
    	public void onApplicationEvent(AbstractApplicationEventForEDN applicationEvent) {
    		try {
    			businessEventPublisher.publishEvent(applicationEvent);
    		} catch (XmlMappingException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    The configuration of this classes as Spring beans and the dependencies between them is shown here:

    <bean id="applicationEventListener" class="com.trivadis.soa.ApplicationEventListenerEDN">
    	<property name="businessEventPublisher" ref="businessEventPublisher"/>
    </bean>
    
    <bean id="businessEventPublisher" class="com.trivadis.soa.BusinessEventPublisherEDN">
    	<property name="businessEventConnection" ref="businessEventConnection"/>
    	<property name="marshaller" ref="marshaller"/>
    </bean>
    
    <oxm:jibx-marshaller id="marshaller" target-class="com.trivadis.cdm.product.Product"/>
    

     

    That’s it! The Java event producer implementation is ready to be tested.

       

      Testing the publishing of an Event


      I have used the Spring Integration Testing support to test the event publishing. The test class PublisherTest implements the Spring ApplicationContextAware interface. This will force the class to implement the setApplicationContext() method, so that the Spring ApplicationContext will be injected at runtime. This ApplicationContext is necessary to publish an event to the Spring event handling mechanism.

      @RunWith(SpringJUnit4ClassRunner.class)
      //ApplicationContext will be loaded from "classpath:/com/trivadis/soa/PublisherTest-context.xml"
      @ContextConfiguration
      public class PublisherTest implements ApplicationContextAware  {
      	
      	private ApplicationContext context;
      
      	public void setApplicationContext(ApplicationContext context) throws BeansException {
      		this.context = context;
      	}
      
      	@Test
      	public void testPublishNewCustomer() throws Exception {
      		Customer cust = new Customer();
      		cust.setId(1);
      		cust.setFirstName("Guido");
      		cust.setLastName("Schmutz");
      		Address adr = new Address();
      		adr.setStreet("Papiermuehlestrasse 73");
      		adr.setZipCode(3014);
      		adr.setCity("Bern");
      		adr.setCountry("Switzerland");
      		cust.setAddress(adr);
      			
      		NewCustomerEvent event = new NewCustomerEvent(this, cust);
      		context.publishEvent(event);
      	}
      }
      

      The test method uses the code shown at the beginning of this post. So the goal of simplifying the event publishing to EDN from Java has been achieved!

      The Enterprise Manager console proves that the event publishing to EDN works!

      temp[7]

    Above the Flow Trace overview and below the details for the EventConsumer is shown. 

        temp[9]

         

        Source code

         

        The code shown in this post is only a proof-of-concept and before using it in a real project, some things like error handling need to be improved. All the source code can be downloaded from here.

        In addition to the NewCustomerEvent shown above, the downloadable version implements two other events, UpdateCustomerEvent and NewProductEvent.

      The download contains he following projects:

        Project IDE/Build Description
        spring-edn Eclipse/Maven all reusable classes described in my post
        spring-edn-sample Eclipse/Maven simulates a Spring application with the Business Event class definition. Depends on the spring-edn project and references these classes when setting up the Spring context at startup time.
        maven-local-repo Maven Handles JAR’s not available in public Maven Repositories but necessary for the build of the two projects. There is a script which will install these JARs into the local repository on your machine. Except of the jms.jar, the JAR files are not provided here (because I don’t know if I would be allowed to), they are copied from your own local installation when running the script.
        EDNProject JDeveloper SOA Suite 11g project defining the Business Event for the Event Delivery Network (EDN) and the composite subscribing to the event on EDN.
        In order for the JiBX customization to work when building the spring-edn-sample project, a patched version of the JiBX maven plugin (1.2.1.1a) is necessary, downloadable from here. For more information see my previous post. For the deployment of the projects, follow these steps:
      1. deploy the EDNProject to a SOA Suite 11g instance.
      2. install the missing JAR’s into your local maven repository by running maven-local-repo/install-jars.bat. Don’t forget to change the environment variable to point to your local installation of FMW
      3. install the necessary artifacts to your local maven repository
      4. create the spring-edn project using mvn install
      5. create the spring-edn-sample project using mvn install.

      Now you can test the installation by running the unit test class as shown above! Hope your are successful!

      Using the new Object/XML Mapping Support of Spring 3.0 with JiBX and Maven

      The Object to XML mapping functionality (OXM) has been moved from Spring Web Services project to the core Spring Framework with version 3.0 of Spring.

      Object/XML Mapping, or O/X mapping for short, is the act of converting an XML document to and from an object. This conversion process is also known as XML Marshalling, XML Serialization or Data Binding. A marshaller serializes an object to XML, and an unmarshaller deserializes XML stream to an object.

      Similar to the Object/Relational support, the Spring O/X mapping support does not implement an O/X mapping. It just offers a consistent abstraction for the most popular O/X frameworks available for Java. By that it allows for easily switching from one O/X mapping framework to another. It currently supports JAXB, Castor, XMLBean, JiBX and XStream.

      I have used the JAXB abstraction together with Spring Web Services before. So for this blog post I have decided to test the O/X support together with JiBX.

      JiBX is a very flexible framework for O/X mapping

      • allowing you to start from existing Java code and generate an XML schema
      • or start from an XML schema and generate Java code
      • or bridge existing code to a schema that represents the same data.

      Setting up Maven and JiBX to generate the source code

       

      For this test, let’s start with the XML schema and generate the Java code from there, which matches the contract-first approach in a SOA.

      <?xml version="1.0" encoding="windows-1252" ?>
      <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                  xmlns:cus="http://www.trivadis.com/cdm/customer"
                  targetNamespace="http://www.trivadis.com/cdm/customer"
                  elementFormDefault="qualified">
        <xsd:element name="customer" type="cus:CustomerType"/>
        <xsd:complexType name="CustomerType">
          <xsd:sequence>
            <xsd:element name="id" type="xsd:integer"/>
            <xsd:element name="firstName" type="xsd:string"/>
            <xsd:element name="lastName" type="xsd:string"/>
            <xsd:element name="address" type="cus:AddressType"/>
          </xsd:sequence>
        </xsd:complexType>
        <xsd:complexType name="AddressType">
          <xsd:sequence>
            <xsd:element name="street" type="xsd:string"/>
            <xsd:element name="city" type="xsd:string"/>
            <xsd:element name="zipCode" type="xsd:integer"/>
            <xsd:element name="country" type="xsd:string"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:schema>
      
      

       

      Starting from a schema and generating Java code and binding definitions is easy with JiBX. The CodeGen tool allows to use both automatic and customized generation for the XML schemas. CodeGen can be used directly from Java, from the Command Line, from an Ant build and there is also a Maven 2  Plugin for JiBX.

      Personally I favor Maven over Ant, so let’s use Maven.

      The first thing we have to do is add the JiBX Maven 2 Plugin to the project POM.

      <plugin>
      	<groupId>org.jibx</groupId>
      	<artifactId>maven-jibx-plugin</artifactId>
      	<version>1.2.1.1</version>
      	<executions>
      		<execution>
      			<id>generate-java-code-from-schema</id>
      			<goals>
      				<goal>schema-codegen</goal>
      			</goals>
      			<configuration>
      				<directory>src/main/xsd</directory>
      				<includes>
      					<include>customer.xsd</include>
      				</includes>
      			</configuration>
      		</execution>
      		<execution>
      			<id>compile-binding</id>
      			<goals>
      				<goal>bind</goal>
      			</goals>
      			<configuration>
      				<directory>target/generated-sources</directory>
      				<load>true</load>
      				<validate>true</validate>
      				<verify>true</verify>
      			</configuration>
      		</execution>
      	</executions>
      </plugin>
      

       

      The POM also needs to include jibx-run and optionally jibx-extras in its dependencies

      <dependency>
      	<groupId>org.jibx</groupId>
      	<artifactId>jibx-run</artifactId>
      	<version>1.2.1</version>
      </dependency>
      <dependency>
      	<groupId>org.jibx</groupId>
      	<artifactId>jibx-extras</artifactId>
      	<version>1.2.1</version>
      </dependency>
      
      

       

      Now with customer.xsd under src/main/xsd we can generate the sources by running mvn generate-sources.

      tmp

       

      We can see from the output that a CustomerType and AddressType class has been generated. Here is the source code of the generated CustomerType class

      package com.trivadis.cdm.customer;
      
      import com.trivadis.cdm.customer.AddressType;
      import java.math.BigInteger;
      
      /** 
       * Schema fragment(s) for this class:
       * <pre>
       * &lt;xs:complexType xmlns:ns="http://www.trivadis.com/cdm/customer" xmlns:xs="http://www.w3.org/2001/XMLSchema" name="CustomerType">
       *   &lt;xs:sequence>
       *     &lt;xs:element type="xs:integer" name="id"/>
       *     &lt;xs:element type="xs:string" name="firstName"/>
       *     &lt;xs:element type="xs:string" name="lastName"/>
       *     &lt;xs:element type="ns:AddressType" name="address"/>
       *   &lt;/xs:sequence>
       * &lt;/xs:complexType>
       * </pre>
       */
      public class CustomerType
      {
          private BigInteger id;
          private String firstName;
          private String lastName;
          private AddressType address;
      
          /** 
           * Get the 'id' element value.
           * 
           * @return value
           */
          public BigInteger getId() {
              return id;
          }
      
          /** 
           * Set the 'id' element value.
           * 
           * @param id
           */
          public void setId(BigInteger id) {
              this.id = id;
          }
      
          /** 
           * Get the 'firstName' element value.
           * 
           * @return value
           */
          public String getFirstName() {
              return firstName;
          }
      
          /** 
           * Set the 'firstName' element value.
           * 
           * @param firstName
           */
          public void setFirstName(String firstName) {
              this.firstName = firstName;
          }
      
          /** 
           * Get the 'lastName' element value.
           * 
           * @return value
           */
          public String getLastName() {
              return lastName;
          }
      
          /** 
           * Set the 'lastName' element value.
           * 
           * @param lastName
           */
          public void setLastName(String lastName) {
              this.lastName = lastName;
          }
      
          /** 
           * Get the 'address' element value.
           * 
           * @return value
           */
          public AddressType getAddress() {
              return address;
          }
      
          /** 
           * Set the 'address' element value.
           * 
           * @param address
           */
          public void setAddress(AddressType address) {
              this.address = address;
          }
      }
      
      

       

      We can see that a POJO has been generated with a reference to another POJO, the AddressType class. This exactly represents the structure of the XML schema. The name of the classes are derived from the Complex Types and the Java data types used are derived from the XML types. Because we have used xs:integer for the id, a Java BigInteger is generated.

      If you are not happy with this default generation, then a lot of things can be customized with JiBX CodeGen!

      So let’s say that we would like to remove the suffix “Type” from the class names, so the generated classes are named Customer and Address and that we like to use a Java Integer instead of the BigInteger.

      Customizations are normally supplied to JiBX CodeGen in the form of an XML document, although certain customizations can alternatively be set via command line parameters. Here is the XML needed for the customizations mentioned before.

      <schema-set prefer-inline="true" generate-all="true"
      	xmlns:xs="http://www.w3.org/2001/XMLSchema" type-substitutions="xs:integer xs:int xs:decimal xs:float">
      	<name-converter strip-suffixes="Type AttributeGroup Group Attributes" />
      </schema-set>
      
      

       

      It specifies some type substitutions as well as suffixes to strip away from names through a name converter. If the suffix stripping is too general, then a more precise way by specifying the mapping from a complex type to the class name can be used:

      <schema-set prefer-inline="true" generate-all="true"
      	xmlns:xs="http://www.w3.org/2001/XMLSchema" type-substitutions="xs:integer xs:int xs:decimal xs:float">
      	<name-converter strip-suffixes="Type AttributeGroup Group Attributes" />
      	<schema name="customer.xsd">
      		<complexType name="CustomerT" class-name="Customer" />
      		<complexType name="AddressT" class-name="Address" />
      	</schema>
      </schema-set>
      
      

       

      In order for Maven to use the customization, we need to change the configuration of the JiBX plugin in the POM and add the <customizations> element with the reference to the customization file.

       

      <configuration>
      	<directory>src/main/xsd</directory>
      	<customizations>
      		<customization>src/main/jibx/customization.xml</customization>
      	</customizations>
      
      

       

      With that in place we can again run mvn clean generate-sources and we should now get a Customer and an Address class.

      Unfortunately the currently available version 1.2.1.1 of the JiBX Maven Plugin does not support the <customizations> element, even though it’s documented. The following error message will be produced: “Command line options must precede all other arguments: error on ‘-c’”. This is a known bug (JIBX-331) with a patch available but not yet applied!

      Thanks to open source, I’ve just got the source code from the repository and applied the patch myself. You can download the patched version 1.2.1.1a from here. Just install it in your local maven repository by running mvn install from the project root.

      Before running mvn clean generate-sources again, you need to switch the version for the JiBX plugin in the project POM from 1.2.1.1 to 1.2.1.1a

      <plugin>
      	<groupId>org.jibx</groupId>
      	<artifactId>maven-jibx-plugin</artifactId>
      	<version>1.2.1.1a</version>
      
      

       

      Finally a Customer and Address class is generated and available to be used!

       

      Combine the JiBX framework with Spring to marshal from Java objects to XML

      To show the O/X mapping of Spring in Action, I just implemented a simple JUnit test class with one method showing the marshalling and unmarshalling from/to a Customer instance.

      Spring abstracts all marshalling operations behind the org.springframework.oxm.Marshaller interface and all unmarshalling operations behind the org.springframework.oxm.Unmarshaller interface.

      For each supported O/X mapping framework there is an implementation of theses two interfaces. In most cases, one class implements both interfaces. For the JiBX framework this is the org.springframework.oxm.jibx.JibxMarshaller class.

      To simplify configuration, Spring also supports XML Schema-based configuration by the OXM namespace. To make the OXM tags available, the appropriate schema has to be referenced first in the preamble of the XML configuration file. Here is the Spring configuration for the JUnit test class.

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:oxm="http://www.springframework.org/schema/oxm"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          http://www.springframework.org/schema/oxm
          http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd">
      
      	<oxm:jibx-marshaller id="marshaller" target-class="com.trivadis.cdm.customer.Customer"/>
      	
      </beans>
      
      

       

      When using the XML Schema-bases configuration, adding the marshaller implementation is a simple one-liner.

      Here is the source code of the JUnit test class using the Spring TestContext framework.

      @RunWith(SpringJUnit4ClassRunner.class)
      //ApplicationContext will be loaded from "classpath:/com/trivadis/soa/PublisherTest-context.xml"
      @ContextConfiguration
      public class MarshallingTest {
      	
      	@Autowired
      	private Marshaller marshaller;
      	@Autowired
      	private Unmarshaller unmarshaller;
      	
      	private static final String FILE_NAME = "C:/temp/customer.xml";
      
      	@Test
      	public void testMarshalUnmarshalCustomer() throws Exception {
      		Customer cust = null;
      		Customer custRead = null;
      		
      		cust = new Customer();
      		cust.setId(1);
      		cust.setFirstName("Guido");
      		cust.setLastName("Schmutz");
      		
      		Address adr = new Address();
      		adr.setStreet("Papiermuehlestrasse 73");
      		adr.setZipCode(3014);
      		adr.setCity("Bern");
      		adr.setCountry("Switzerland");
      		
      		cust.setAddress(adr);
      
      		FileOutputStream os = null;
              try {
                  os = new FileOutputStream(FILE_NAME);
                  marshaller.marshal(cust, new StreamResult(os));
              } finally {
                  if (os != null) {
                      os.close();
                  }
              }
              
              FileInputStream is = null;
              try {
                  is = new FileInputStream(FILE_NAME);
                  custRead = (Customer) this.unmarshaller.unmarshal(new StreamSource(is));
              } finally {
                  if (is != null) {
                      is.close();
                  }
              }
              
              Assert.assertEquals(cust.getId(), custRead.getId());
              Assert.assertEquals(cust.getFirstName(), custRead.getFirstName());
              Assert.assertEquals(cust.getLastName(), custRead.getLastName());
              Assert.assertEquals(cust.getAddress().getStreet(), custRead.getAddress().getStreet());
              Assert.assertEquals(cust.getAddress().getZipCode(), custRead.getAddress().getZipCode());
              Assert.assertEquals(cust.getAddress().getCity(), custRead.getAddress().getCity());
              Assert.assertEquals(cust.getAddress().getCountry(), custRead.getAddress().getCountry());
      	}
      }
      

      The JUnit test class defines a dependency on the Marshaller as well as the Unmarshaller. Using @Autowired, the instance defined in the Spring configuration is automatically injected when running the test. The only test method creates an instance of Customer, marshals it to XML and stores it in a file. Then this file is read, unmarshalled from XML to a new Customer instance and compared with the original one.

      Before the test can be run, the project needs to be built by running mvn package.  This will also run the JiBX binding compiler which will enhance the Java byte code of the generated classes, i.e. Customer and Address, with the binding information necessary at runtime.

       

      The example project can be downloaded from here.

      The patched version (1.2.1.1a) of the Maven 2 JiBX Plugin project can be downloaded from here.