Wednesday, August 10, 2016

An introduction to working with JAXB

I am in the process of migrating a few modules that are dependent on Apache XMLBeans to JAXB. It has been an exciting and challenging few days. I thought of jotting down a few important things I came across for anyone who might find it useful in the future.

First of all, let us look at setting up the maven plugin for the JAXB code generation. As of the time of writing this post, I came across two maven plugins;
Ended up using the first one as I found the configuration to be quite straightforward.

Your maven project structure will be as follows;
Project Folder->src->main->xsd
This will hold all the XSD files from which you would want to generate the JAXB objects.

Project Folder->src->main->xjb
This will holder your “bindings.xml” file, which is your data binding file used for any customization required as part of running the JAX generation task(xjc).

The plugin configuration for maven will be as follows;
 
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
     <version>2.2</version>
    <executions>
     <execution>
      <id>xjc</id>
      <goals>
       <goal>xjc</goal>
      </goals>
     </execution>
    </executions>
    <configuration>
     <target>2.1</target>
     
     <sources>
      <source>src/main/xsd</source>
     </sources>
     
    </configuration>
  </plugin>


  • One thing that we were quite used with XMLBeans was the “isSet” type of methods for all optional elements which will check if the element is set or not. By default JAXB does not generate this method and you have to end up using the not null condition on each element. Thankfully, the binding configuration allows for this with the following;

<jxb:bindings 
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    jxb:extensionBindingPrefixes="xjc"
    version="2.1">
<jxb:globalBindings  generateIsSetMethod="true"
</jxb:globalBindings>
</jxb:bindings>


  • By default, JAXB does not generate Java enumerations for the enumerations defined on the XSD files. The sad part is I could not find a way to apply this generation at a global level and could only handle it per XSD. But with XMLBeans, this was automatically done. In order to generate Java enumerations, the following should be done;
Sample XSD:

<xs:complexType name="EndpointType">
  <xs:attribute name="protocol">
   <xs:simpleType>
    <xs:restriction base="xs:string">
     <xs:enumeration value="HTTP"/>
     <xs:enumeration value="HTTPS"/>
     <xs:enumeration value="PAYLOAD"/>
    </xs:restriction>
   </xs:simpleType>
  </xs:attribute>
 </xs:complexType>


JAXB binding:
 
<jxb:bindings 
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    jxb:extensionBindingPrefixes="xjc"
    version="2.1">
<jxb:bindings schemaLocation="../xsd/testconfig.xsd">
       
  <jxb:bindings node="//xs:complexType[@name='EndpointType']/xs:attribute[@name='protocol']/xs:simpleType">
               <jxb:typesafeEnumClass name="Protocol" />
        </jxb:bindings>
 
   </jxb:bindings>
</jxb:bindings>

schemaLocation – This is the relative path to the XSD I want to refer to. Since my “bindings.xml” resided in the “xjb” directory, I had to go one step up and go into the XSD directory to get the required XSD file.

node – Here you need to provide the xquery path of the simple type that has the enumeration defined. If you cross check this with the XSD provided, you will figure out how the XQuery path retrieves the given element.

Note: If in any event, your xpath returns multiple elements with the same name, you can still handle this by introducing the element multiple=”true” on the <jxb:bindings> element.
E.g : <jxb:bindings node="//xs:complexType[@name='EndpointType']/xs:attribute[@name='protocol']/xs:simpleType" multiple="true">


typesafeEnumClass – On this element you can provide the Java enumeration name to be generated.

  • XMLBeans by default converts all XSD date and date time elements to a Java Calendar object. With JAXB however, by default the XMLGregorianCalendar is used. Yet again the global bindings came to the rescue and this was handled with the below configuration which converted all XSD date elements to a Java Calendar object.


<jxb:bindings 
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    jxb:extensionBindingPrefixes="xjc"
    version="2.1">

<jxb:globalBindings>

   <jxb:javaType name="java.util.Calendar" xmlType="xs:dateTime"
            parseMethod="javax.xml.bind.DatatypeConverter.parseDateTime"
            printMethod="javax.xml.bind.DatatypeConverter.printDateTime"/>

        <jxb:javaType name="java.util.Calendar" xmlType="xs:date"
            parseMethod="javax.xml.bind.DatatypeConverter.parseDate"
            printMethod="javax.xml.bind.DatatypeConverter.printDate"/>

        <jxb:javaType name="java.util.Calendar" xmlType="xs:time"
            parseMethod="javax.xml.bind.DatatypeConverter.parseTime"
            printMethod="javax.xml.bind.DatatypeConverter.printTime"/>
    </jxb:globalBindings>

</jxb:bindings>


  • If there is a need to make your JAXB objects serializable, this can be achieved with the following global binding configuration;

<jxb:bindings 
   xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    jxb:extensionBindingPrefixes="xjc"
    version="2.1">

 <jxb:globalBindings >
 <xjc:serializable />
  
  </jxb:globalBindings>
 
 
</jxb:bindings>




The element that does the trick is the “<xjc:serializable/>” element.


  • With JDK 1.8, I faced an issue whereby if one of your XSD’s had an import for another schema to retrieve another XSD via HTTP, this was being blocked. An excerpt of the error thrown out was “because 'http' access is not allowed due to restriction set by the accessExternalDTD property”. The work-around in this case was to use the following maven plugin to set the VM arguments required to bypass this restriction. More information on this issue can be found here.

<plugin>
    <!-- We use this plugin to ensure that our usage of the
    maven-jaxb2-plugin is JDK 8 compatible in absence of a fix
    for https://java.net/jira/browse/MAVEN_JAXB2_PLUGIN-80. -->
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
   <version>1.0.0</version>
    <executions>
        <execution>
            <id>set-additional-system-properties</id>
            <goals>
                <goal>set-system-properties</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <properties>
            <property>
                <name>javax.xml.accessExternalSchema</name>
                <value>file,http</value>
            </property>
    <property>
                <name>javax.xml.accessExternalDTD</name>
                <value>file,http</value>
            </property>
        </properties>
    </configuration>
</plugin>


That is about it. I will keep updating this post as I go on. As always, your feedback on the same is always much appreciated.

Thank you for reading, and have a good day everyone.

An introduction to the Oracle Service Bus

We are in the process of designing a new system for a telecommunication provider where we have looked at the Oracle Service Bus (OSB) to be used as the enterprise service bus. One of the first plus points for me was the amazing tooling support it encompasses. Oracle has integrated all their enterprise integration software stack into a cohesive whole by bundling it up as the Oracle SOA Suite. In this article, the focus would be on the Oracle OSB 11g which is part of the Oracle SOA Suite 11g. There are considerable changes that has been done with the new Oracle SOA Suite 12c which we will not delve into in this article. However, one feature I love about the new Oracle SOA Suite 12c is the fact that the developers can use JDeveloper to develop BPEL(Business process execution language) and OSB code in one IDE(Integrated Development Environment).

Couple of main components one needs to be aware of with the OSB is as follows;

Proxy Service
A proxy service as its name implies, is a service that is hosted to the external parties which acts as a facade for an internal service. By having a proxy service, you have more control over the changes in your internal services as the proxy service can do the required transformations if your internal services ever change.

Business Service
A business service, in terms of the OSB, represents an internal application service. It can be a WebService, JMS queue/topic, REST service, FTP service and many more. The business service will encompass the functionality to call the actual service.

So the scenario we will focus on this article is as follows;
  1. We have an internal service that returns subscriber information if the user passes in either the MSISDN or the SIM Card number and depending on the input, data will be fetched and returned.
  2. This service will have to be exposed to the external party in a more meaningful manner by making use of a proxy service.
The sample project can be downloaded here.

First of all, we create the business service which will act as the facade to our internal service. In your OSB project,  create the following four folders;
  • proxy
  • business
  • transformation
  • wsdl
Then we need to copy the internal service WSDL and the proxy service WSDL created for this example into the “wsdl” folder.

Configuring the business service
Right click on the “business” folder and select New->Business Service. When the business service is created, you will then first be presented with the “General” tab. In this we do the following;

  • Select “WSDL Web Service” and click on browser. Then select “Browse”, select the WSDL file and you will be presented with two options. Select the one ending with “(port).


  • Then go the “Transport” tab and change the URI as http://localhost:8088/mockInstalledBaseSubscriberClassificationQueryWSServiceSoapBinding. This is because we will use the SOAPUI mock service feature to test this out and the URI represents the mock service endpoint of SOAPUI for the service represented by the WSDL. 
  • The SOAPUI project use for this example can be downloaded from here.
That is all we need to do to configure our business service. Then we move onto our proxy service where all the action takes place.

Configuring the proxy service
  • Right click on the “proxy” folder created, select New->Proxy Service and provide a valid name. 
  • In the “General” tab, select “WSDL Web Service” and click on browse.
  • Now in the proxy service, you need to select the proxy WSDL file we have created which will be exposed to the external clients.























  • Go to the “Message Flow” tab. In that tab, first drag a “Route” element from the “Design Palette” on the right side. 
  • Afterwards, drag a “Routing” element into the “Route” element.
  • Click on the “Routing” element and in the bottom pane, go into the “Properties” tab where you will provide the business service that this proxy service will access and the operation name.

  • The result will be as follows;







  • Then drag a “Replace” action into the “Request Action” component.
  • Before we provide the information on the “Properties” tab for the “Replace” action, we need to create the XQuery transformation files which will map the proxy service request to the business service request and then the business service response back to the proxy service response.
  • Right click on the “transformation” folder and select New->XQuery Transformation. Enter a valid name. This should be done for both the request and response transformation files.
  • The request transformation file used is as follows;

 
(:: pragma bea:global-element-parameter parameter="$fetchSubscriber1" element="ns2:FetchSubscriber" location="../wsdl/SubscriberProxyService.wsdl" ::)
(:: pragma bea:local-element-return type="ns1:InstalledBaseSubscriberClassificationQuery/ns0:InstalledBaseSubscriberClassificationQuery" location="../wsdl/subscriber_classfication.wsdl" ::)

declare namespace ns2 = "http://www.example.org/SubscriberProxyService/";
declare namespace ns1 = "http://www.openuri.org/";
declare namespace ns0 = "http://mtnsa.co.za/si/IB/IBSubscriberClassificationQuery";
declare namespace xf = "http://tempuri.org/OSB%20training%201/transformation/subscriberrequest/";

declare function xf:subscriberrequest($fetchSubscriber1 as element(ns2:FetchSubscriber))
    as element() {
     <ns1:InstalledBaseSubscriberClassificationQuery>
        <ns0:InstalledBaseSubscriberClassificationQuery>
            <ns0:Request>
              
                    {
                        if (data($fetchSubscriber1/EquipmentType) = "MSISDN") then
                           <ns0:MSISDN>  { (data($fetchSubscriber1/EquipmentValue))}</ns0:MSISDN>
                        else 
                           <ns0:SIMCard> { data($fetchSubscriber1/EquipmentValue)}</ns0:SIMCard>
                    }

            </ns0:Request>
        </ns0:InstalledBaseSubscriberClassificationQuery>
        </ns1:InstalledBaseSubscriberClassificationQuery>
};

declare variable $fetchSubscriber1 as element(ns2:FetchSubscriber) external;

xf:subscriberrequest($fetchSubscriber1)

Here as you can see, we check if the equipment type is equal to “MSISDN” and then set the appropriate element on the business service.

  • The response transformation file used is as follows;
 
(:: pragma bea:global-element-parameter parameter="$installedBaseSubscriberClassificationQueryResponse1" element="ns1:InstalledBaseSubscriberClassificationQueryResponse" location="../wsdl/subscriber_classfication.wsdl" ::)
(:: pragma bea:global-element-return element="ns2:FetchSubscriberResponse" location="../wsdl/SubscriberProxyService.wsdl" ::)

declare namespace ns2 = "http://www.example.org/SubscriberProxyService/";
declare namespace ns1 = "http://www.openuri.org/";
declare namespace ns0 = "http://mtnsa.co.za/si/IB/IBSubscriberClassificationQuery";
declare namespace xf = "http://tempuri.org/OSB%20training%201/transformation/subscriberresponse/";

declare function xf:subscriberresponse($installedBaseSubscriberClassificationQueryResponse1 as element(ns1:InstalledBaseSubscriberClassificationQueryResponse))
    as element(ns2:FetchSubscriberResponse) {
        <ns2:FetchSubscriberResponse>
            <TradeCustomerCode>{ data($installedBaseSubscriberClassificationQueryResponse1/ns0:InstalledBaseSubscriberClassificationQuery/ns0:Response/ns0:Subscriber/@ServiceProviderCode) }</TradeCustomerCode>
            <PackageCode>{ data($installedBaseSubscriberClassificationQueryResponse1/ns0:InstalledBaseSubscriberClassificationQuery/ns0:Response/ns0:Subscriber/ns0:Package/@ProductCode) }</PackageCode>
            <PaymentOption>{ data($installedBaseSubscriberClassificationQueryResponse1/ns0:InstalledBaseSubscriberClassificationQuery/ns0:Response/ns0:Subscriber/@PaymentOption) }</PaymentOption>
        </ns2:FetchSubscriberResponse>
};

declare variable $installedBaseSubscriberClassificationQueryResponse1 as element(ns1:InstalledBaseSubscriberClassificationQueryResponse) external;

xf:subscriberresponse($installedBaseSubscriberClassificationQueryResponse1)

This is a simple transformation where we map the response elements to the proxy response elements as required.
    Now we move back to our proxy service, click on the “Replace” action, go to the “Properties” tab.
    • In the “In Variable” insert the value “body”.
    • Click on the “Expression” link. Go to the “XQuery Resources” tab, click on “Browse” and select the request transformation file.
    • In the “Variable Structures” component on the right side, expand the “body” element, and then select the request element and drag and drop it into the “Binding” text box as follows;
















    • Then select “OK” which will take you back to the “Properties” tab.
    • Select “Replace node contents” radio button. The end result will look as follows;


    • Now let us drag and drop a “Replace” action to the “Response Action” component.
    • Same as before, select the response transformation “$body/ins:InstalledBaseSubscriberClassificationQueryResponse”.
    • You will now get an error stating that the “ins” namespace is not recognized.
    • In order to resolve that, in the same “Properties” tab, select the tab “Namespaces” and click on add. Enter the prefix as “ins” and the URI as “http://www.openuri.org/”. 





    And that is it. Now we can test out the functionality. Before you do, remember to first start the mock service created on SOAP UI. 
















    Now let us log into the service bus console, go to the proxy service and launch the test console. This is the result that I got by running a sample;






















    You can see a trace of what exactly happened if you go further down on the same screen within the “Invocation Trace” section. The request and response transformation done by the OSB can be seen as follows;





















    That ends our introduction to the Oracle Service Bus. If you do have any queries on the same, please do not hesitate to leave a comment by and I will respond to it as soon as possible. Also, if there are any areas of improvement you may see, kindly leave your feedback as well which is always much appreciated.