How to use Unitils with PowerMock and Mockito all together

powermock

Mocking static methods without pain.

Sometimes you need to mock static methods like when you are using builders, or utility class instantiated through their factory method, inside a method that has to be unit tested.  Mostly this ain’t no issue, but if that builder or utility class depends itself on an injected class by a dependency injection framework like Spring, then you’ll get a NullPointerException when executing the test, so you can’t use the real implementation.  This is normal because you can’t inject that instance into that helper class or builder as it isn’t the tested object, so we need to find a way to mock that class.

I now had an issue with an EventHandler that has to be unit tested. The  handle method which has to be tested calls a factory method named anEventPoster to get an instance of the EventPoster so I can post an event it which internally will delegate it to the post method of the EventBus.  Unfortunately, the EventPoster depends on an EventBus which is @Autowired (or @Inject when using CDI in Spring). When unit testing, you don’t have a dependency injection mechanism, which would mean you could only test it through an integration test.  You can use Unitils, but this only works on the tested class, not on the classes instantiated through factory methods used inside the tested class.  So I start looking for an elegant solution which allows me to still use Unitils all together with Mockito and PowerMock, which in past I knew it was impossible due to the fact that you can only have one Runner (e.g. @RunWith) specified on your JUnit test class.  That’s were @PowerMockRunnerDelegate comes to the rescue, which is available since PowerMock version 1.6.0.

The first important thing to check is which versions of PowerMock and Mockito you are using, because both have to be compatible.  I used the latest versions of both libraries:

<dependency>
 <groupId>org.mockito</groupId>
 <artifactId>mockito-all</artifactId>
 <version>1.10.19</version>
</dependency>
<dependency>
 <groupId>org.powermock</groupId>
 <artifactId>powermock-api-mockito</artifactId>
 <version>1.6.2</version>
</dependency>
<dependency>
 <groupId>org.powermock</groupId>
 <artifactId>powermock-module-junit4</artifactId>
 <version>1.6.2</version>
</dependency>

I also tested the some solution with version 1.6.0 and 1.6.1 but it didn’t work.  I only got it running with the latest version of PowerMock and Mockito.

Now you must define your test class as follow:


package be.dabla.export;

import static be.dabla.bus.EventPoster.anEventPoster;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InOrder;
import org.mockito.MockitoAnnotations;
import org.mockito.Mock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.unitils.UnitilsBlockJUnit4ClassRunner;
import org.unitils.inject.annotation.InjectIntoByType;
import org.unitils.inject.annotation.TestedObject;

import be.dabla.command.ExportCommand;
import be.dabla.event.ExportedEvent;
import be.dabla.bus.EventPoster;

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(UnitilsBlockJUnit4ClassRunner.class)
@PowerMockIgnore("javax.management.*")
@PrepareForTest(EventPoster.class)
public class ExportCommandHandlerTest {
    private static final String ID = "ID";

    @Mock
    private ExportCommand command;
    @Mock
    private EventPoster eventPoster;

    @Mock
    @InjectIntoByType
    private Exporter exporter;

    @TestedObject
    private ExportCommandHandler handler;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        mockStatic(EventPoster.class);
        when(anEventPoster()).thenReturn(eventPoster);
    }

    @Test
    public void handle() throws Exception {
        when(command.getId()).thenReturn(ID);

        handler.handle(command);

        InOrder inOrder = inOrder(exporter, eventPoster);
        inOrder.verify(exporter).export(ID);
        inOrder.verify(eventPoster)
               .post(any(ExportedEvent.class));
    }
}

The tested class looks like this using the EventPoster through it’s factory method.

package be.dabla.export;

import static be.dabla.event.ExportedEvent.exportedEvent;
import static be.dabla.bus.EventPoster.anEventPoster;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.eventbus.AllowConcurrentEvents;
import com.google.common.eventbus.Subscribe;

import be.dabla.export.ExportCommand;
import be.dabla.bus.EventHandler;

@Component
public class ExportCommandHandler implements EventHandler {

    @Autowired
    private Exporter exporter;

    @Subscribe
    @AllowConcurrentEvents
    public void handle(ExportCommand event) {
        exporter.export(event.getId());

        anEventPoster().post(exportedEvent(event.getId()));
   }
}

Also note the annotation named @PowerMockIgnore, this was needed because when running the tests in Maven I got the following exception:

Failed to instantiate [ch.qos.logback.classic.LoggerContext]
Reported exception:
java.lang.LinkageError: loader constraint violation: loader (instance of org/powermock/core/classloader/MockClassLoader) previously initiated loading for a different type with name "javax/management/MBeanServer"

I found the solution to this problem on stackoverflow.

I wanted to share this solution as it maybe useful to others who also encountered this issue.  It’s also a pity if you have to alter an elegant design, like add a factory bean because you can’t mock it.  In this case a factory bean would have been a work around solution, but I found it a bit overkill to have a factory class for such a simple class as the EventPoster.

I’ll try to add a complete example on GitHub when I find some spare time.

Tagged , , , , , , , ,

Mapping SDO DataObjects as Entities with JPA and EclipseLink

In the quest to enable SDO DataObject’s to be stored and retrieved from the database with JPA, I searched for a simpler solution to enable to map the SDO DataObject’s directly without the need of separate Java Beans as Entities as this leads to a lot of overhead and boiler plate code just to convert from Java Entity Beans to SDO DataObject’s and vice versa.

Below you’ll find a UML class diagram which shows most classes involved in the process as described above.  When mapping the SDO DataObject’s directly through JPA, all the classes/interfaces defined outside the green area will become obsolete.  The most important change is that the methods marked in red, which contain the boiler plate code to do the conversion from SDO DataObject’s to Entities and vice versa, and which have to be implemented for each Java Entity and SDO DataObject, aren’t needed anymore.

 

Now I’ll elaborate the code snippets referring to the two methods marked in red containing the conversion code.  The first snippet contains the code of the method named toDataObject to create an SDO DataObject from the Java Entity bean.  This code is essential to be able to expose the persisted Java Entity Bean as an SDO DataObject.

Secondly you’ll see a snippet containing the code of the method named toEntity of the SDO DataObject implementation. This code will recreate a Java Bean Entity from the SDO DataObject so that it can be persisted through JPA.

As you can conclude from the code above, this is a lot of repeated code that you have to rewrite for each entity and which doesn’t respect the DRY principle of course.  Now the main challenge when mapping SDO DataObject’s as JPA Entities is that:

  1. First of all, in JPA you, can’t map Entities through interfaces.
  2. Secondly, when you map a Java class with JPA, the class will always be instantiated through the default zero argument constructor.

Unfortunately, when you instantiate an SDO DataObject implementation with the default constructor, not all properties of the DataObject will be initialized which leads to a lot of Nullpointer exceptions at runtime. To instantiate an SDO DataObject, you need to use commonj.sdo.helper.DataFactory class. Also make sure that before you try to instantiate the SDO DataObject through the factory class that the SDO DataObject has been registered with it’s corresponding XSD defintion. To do this you need to use the commonj.sdo.helper.XSDHelper class. This class will load the given XSD and register it with the SDO DataObject interface for use with the DataFactory.

Also, JPA doesn’t know that it has to invoke the factory method. Fortunately in EclipseLink, which is by the way also the JPA reference implementation, there is a way to customize how Entities are being instantiated when loaded from the database through the EntityManager. This can be done through the EclipseLink annotation called org.eclipse.persistence.annotations.Customizer. You can also do this through the eclipselink-orm.xml file if you don’t want to mix JPA annotations with EclipseLink dependent annotations. For this example I used the annotation method as I personally find it more convenient to showcase.

The org.eclipse.persistence.annotations.Customizer annotation needs an class argument which implements the org.eclipse.persistence.config.DescriptorCustomizer interface.
That last interface is the important one which you need to implement and allows you to customize the way how Java Entities are being instantiated through EclipseLink. Below you’ll find an extract of that implementation. Also note that I don’t use the DataFactory here. That’s because EclipseLink uses an Instantiation Policy to define customization’s and already has an Instantiation Policy implementation for SDO DataObject’s.

Now the only thing we need to do is to map the SDO DataObject’s as JPA Entities and use the Customizer annotation, which is shown here:

This approach has also been applied in the latest commit of the EJB SDO SERVICE, which has made the implementation of the AbstractService class a lot simpler.  The complete source code can be found on GitHub.

Tagged , ,

Integrating JPA based SDO’s with ADF frontend

Introduction

In the previous post we successfully deployed JPA 2 based SDO‘s which were remotely accessible through EJB as well as through SOAP.  We’re also able to use the Oracle BPEL extensions to create, update, delete and retrieve SDO entities from the SOA Suite, just like it’s the case with Business Components based SDO’s.

Now the last goal is to reuse the same SDO service from the ADF frontend so that we have a clean SOA solution.  To do that I opted to write a custom implementation of the javax.faces.model.DataModel class which we will bind with the ADF table component, just like we would do in standard JSF applications.  The implementation will have to support pagination, sorting and filtering.

Service

The first issue with pagination is that you need how many records are contained in the table you want to paginate.  So to resolve this, I added for each SDO a count method which also has a FindCriteria parameter as an argument as those will also influence the total number of records that will be returned.  I’ve also added a generic Service interface to the SDO service implementation which will only be accessible through EJB as JAX-WS doesn’t support the use of generic methods.  That’s also why I added the WebService(exclude=true) annotations to each method to prevent JAX-WS to try to expose those methods at deployment, which would of course fail.  Now the main advantage is that all the methods of the remote EJB interface are generic for any SDO implementation.

Here is a short description of the available methods:

  • get: retrieve the entity for the given primary key
  • create: create the passed entity
  • update: updates the passed entity
  • delete: removes the passed entity
  • count: counts the total number of available entities for the given criteria
  • find: returns a list of entities for the given criteria with support for paging

Model

Before I started with the implementation, I’ve searched across the net to see if there were already some existing DataModel implementations with support for pagination.  That’s when I found the following example on Apache Wiki: http://wiki.apache.org/myfaces/WorkingWithLargeTables.  I’ve made some modifications to the example so that it has a common fetch method implementation based on the above defined interface.  This has the main advantage that the PagedListDataModel is reusable across different SDO’s without have to re-implement the fetchPage method over and over again (DRY methodology).  You’ll notice that the method counts as well as retrieves the entities so that pagination is automatically enabled.  Beside that there are also two important parts within that method, which enable sorting and filtering.

To enable the sorting aspect of the DataModel, I implemented the required methods like the get/setSortCriteria.  Even though the sorting was working, it was stuck in an infinite loop.  To bypass this issue, I had to change the base class named javax.faces.model.DataModel to the base class named org.apache.myfaces.trinidad.model.CollectionModel from the trinidad library.  Another side effect was that when the sorting was enabled, the pagination was broken.  To resolve this, I also had to implement the get/setRowKey methods.

Once the sorting was working, I only had to implement the filtering functionality.  To achieve this, you have to write an implementation of the oracle.adf.view.rich.model.FilterableQueryDescriptor class.  In the current example, I only implemented the filter criteria aspect, which was enough to enable the filtering in the ADF table. Then in the PagedListDataModel class, I added a setter and getter method for FilterableQueryDescriptor attribute.  I’ve also wrote a reset method, which invalidates the current Data Page when the filter criteria is changed, otherwise the cached result would always be returned and no query would be performed against the backend.

Here you can see the code of the custom DataModel:

View

Now that the custom DataModel is ready, I only have to implement it for the EmployeesSDO entity.

Now let’s write the EmployeesBean so that we can use it with an ADF table component.

Once the JSP page is written, we can run it on the IntegratedWeblogic server to see the result.

Once the page is loaded, you should see something similar in your browser.

Now you can do for example sorting or do some filtering or search for a specific record as shown in the overview below.

Cool, isn’t it?🙂 There is of course still room for improvement.

You can find the complete source code of this project on my GitHub.

Tagged , , , , , , , , , , , , ,

Exposing an EJB SDO Service Interface as a SOAP WebService – Part 2

Introduction

This is the second part of exposing an EJB SDO Service Interface as a SOAP Service, which was originally based on an example made by Edwin Biemond.

This time I completely rewrote the HrSessionEJBBean, which is now based on JPA 2. Beside that it also respects the same interface as those found in the ADF-BC based ApplicationModules.  The purpose of this is to be able to use the Oracle BPEL extensions like BindEntity, CreateEntity and RemoveEntity like described here: http://albinoraclesoa.blogspot.be/2012/07/crud-operations-with-entity-variable.html

The code is based on generics, so that the same logic can be easily reused for any POJO based entity.  The AbstractService class is still Work In Progress and not every method has been fully tested yet.  The find-operation has been successfully tested in the HrSessionEJBClientSDO class under the TestEJB project, from SoapUI and from BPEL with the BindEntity Oracle BPEL extension.

Setup

Before you start, you’ll have to enable JPA 2 on Weblogic.  The libraries are already present on Weblogic, you only need to enable them.  To do so, just do as explained in the following link here: http://danielveselka.blogspot.be/2011/02/enable-jpa2-in-weblogic-1034.html

Interface

The new project can be downloaded at: https://github.com/dabla/ejb-jpa2-sdo-service

To respect the same interface as the one generated by the ADF-BC based SDO’s, I implemented the following methods for each entity:

  • getEntitySDO
  • createEntitySDO
  • updateEntitySDO
  • deleteEntitySDO
  • mergeEntitySDO
  • findEntitySDO
  • processEntitySDO
  • processCSEntitySDO

You’ll have to define all methods mentioned above for each entity.  Luckily, the implementation logic for each of these methods has already been written in the AbstractService class, so you’ll only need to pass the parameters. For this example, the methods have been defined in the HrSessionEJB interface for the Employees and Departments entities, just like in the original example.

The WSDL should look like this:

XSD

Beside modifying the interface, I also modified the original XSD’s, namely:

  • DepartmentsSDO.xsd
  • EmployeesSDO.xsd

Here is an extract of the DepartmentsSDO.xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            targetNamespace="/nl.amis.sdo.jpa.entities/"
            xmlns:tns="/nl.amis.sdo.jpa.entities/"
            xmlns="/nl.amis.sdo.jpa.entities/" xmlns:sdoJava="commonj.sdo/java"
            sdoJava:package="nl.amis.sdo.jpa.entities">
   <xsd:import schemaLocation="classpath:/xml/sdoJava.xsd" namespace="commonj.sdo/java"/>
   <xsd:import schemaLocation="classpath:/xml/sdoXML.xsd" namespace="commonj.sdo/xml"/>
   <xsd:include schemaLocation="EmployeesSDO.xsd"/>
   <xsd:complexType name="DepartmentsSDO">
      <!-- annotation is required when using entity binding from BPEL to be able to define bpelx:key-->
      <xsd:annotation>
          <xsd:appinfo source="http://xmlns.oracle.com/adf/svc/metadata/">
              <key xmlns="http://xmlns.oracle.com/adf/svc/metadata/">
                  <attribute>departmentId</attribute>
              </key>
          </xsd:appinfo>
      </xsd:annotation>
      <xsd:sequence>
         <xsd:element name="departmentId" type="xsd:long" minOccurs="0"/>
         <xsd:element name="departmentName" type="xsd:string" minOccurs="0"/>
         <xsd:element name="employeesList" type="tns:EmployeesSDO" minOccurs="0" maxOccurs="unbounded"/>
         <xsd:element name="locationId" type="xsd:long" minOccurs="0"/>
         <xsd:element name="manager" type="tns:EmployeesSDO" minOccurs="0"/>
      </xsd:sequence>
   </xsd:complexType>
   <xsd:element name="departmentsSDO" type="tns:DepartmentsSDO"/>
</xsd:schema>

Mind the annotation element in the beginning of the DepartmentsSDO type definition (*).  This one is needed to be able to define a key element within the BindEntity in BPEL like shown in the extract below which I will explain in the BPEL part:

<bpelx:bindEntity name="BindEmployeesEntity" variable="employeesEV">
   <!-- note here that the employeeId is set with hard coded value 10 for illustration -->
   <bpelx:key keyname="ns2:employeeId">string('10')</bpelx:key>
</bpelx:bindEntity>

Beside that I also needed to add the following BC4J XSD’s (located under the “WEB-INF/wsdl/META-INF/wsdl” directory) to be able to use the FindCriteria and FindControl elements within the find operation and the ProcessData and ProcessControl elements within the process methods:

  • ServiceException.wsdl (don’t think it’s actually needed but added it anyway, will clean up later)
  • ServiceException.xsd
  • BC4JService.xsd
  • BC4JServiceCS.xsd

In the service implementation named HrSessionEJBBean, I also needed to preload those XSD’s just like it was already the case for the Employees and Departments XSD’s.  I’ve tried to load all XSD’s at once with the SDOHelper by only loading the main HrSessionEJBBeanWS.xsd, which succeeded, but at runtime the EclipseLink-45010 exception reappeared, so I went back to the original solution and loaded all XSD’s manually.

Bellow an extract on how those XSD’s are loaded, mind that the order is important:

static {
    synchronized (HrSessionEJBBean.class) {
      try {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        XSDHelper.INSTANCE.define(loader.getResourceAsStream("META-INF/wsdl/ServiceException.xsd"),
                                  "META-INF/wsdl/");
        XSDHelper.INSTANCE.define(loader.getResourceAsStream("META-INF/wsdl/BC4JService.xsd"),
                                  "META-INF/wsdl/");
        XSDHelper.INSTANCE.define(loader.getResourceAsStream("META-INF/wsdl/BC4JServiceCS.xsd"),
                                  "META-INF/wsdl/");
        XSDHelper.INSTANCE.define(loader.getResourceAsStream("nl/amis/sdo/jpa/entities/EmployeesSDO.xsd"),
                                  "nl/amis/sdo/jpa/entities/");
        XSDHelper.INSTANCE.define(loader.getResourceAsStream("nl/amis/sdo/jpa/entities/DepartmentsSDO.xsd"),
                                  "nl/amis/sdo/jpa/entities/");
        XSDHelper.INSTANCE.define(loader.getResourceAsStream("nl/amis/sdo/jpa/services/HrSessionEJBBeanWS.xsd"),
                                  "nl/amis/sdo/jpa/services/");
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
  }

WSDL

Below I’ll show the essential parts within the service definition which you can copy/paste and perform search/replace on for each entity.

This is an extract for the type definitions within the HrSessionEJBBeanWS.xsd:

<!-- BEGIN SDO Elements -->
 <element name="getEmployeesSDO">
 <complexType>
 <sequence>
 <element name="employeeId" type="long"/>
 </sequence>
 </complexType>
 </element>
 <element name="getEmployeesSDOResponse">
 <complexType>
 <sequence>
 <element name="result" type="ns0:EmployeesSDO"/>
 </sequence>
 </complexType>
 </element>
 <element name="createEmployeesSDO">
 <complexType>
 <sequence>
 <element name="employees" type="ns0:EmployeesSDO"/>
 </sequence>
 </complexType>
 </element>
 <element name="createEmployeesSDOResponse">
 <complexType>
 <sequence>
 <element name="result" type="ns0:EmployeesSDO"/>
 </sequence>
 </complexType>
 </element>
 <element name="updateEmployeesSDO">
 <complexType>
 <sequence>
 <element name="employees" type="ns0:EmployeesSDO"/>
 </sequence>
 </complexType>
 </element>
 <element name="updateEmployeesSDOResponse">
 <complexType>
 <sequence>
 <element name="result" type="ns0:EmployeesSDO"/>
 </sequence>
 </complexType>
 </element>
 <element name="deleteEmployeesSDO">
 <complexType>
 <sequence>
 <element name="employees" type="ns0:EmployeesSDO"/>
 </sequence>
 </complexType>
 </element>
 <element name="deleteEmployeesSDOResponse">
 <complexType>
 <sequence/>
 </complexType>
 </element>
 <element name="mergeEmployeesSDO">
 <complexType>
 <sequence>
 <element name="employees" type="ns0:EmployeesSDO"/>
 </sequence>
 </complexType>
 </element>
 <element name="mergeEmployeesSDOResponse">
 <complexType>
 <sequence>
 <element name="result" type="ns0:EmployeesSDO"/>
 </sequence>
 </complexType>
 </element>
 <element name="findEmployeesSDO">
 <complexType>
 <sequence>
 <element name="findCriteria" type="ns3:FindCriteria"/>
 <element name="findControl" type="ns3:FindControl"/>
 </sequence>
 </complexType>
 </element>
 <element name="findEmployeesSDOResponse">
 <complexType>
 <sequence>
 <element name="result" type="ns0:EmployeesSDO" minOccurs="0" maxOccurs="unbounded"/>
 </sequence>
 </complexType>
 </element>
 <element name="processEmployeesSDO">
 <complexType>
 <sequence>
 <element name="changeOperation" type="string"/>
 <element name="employees" type="ns0:EmployeesSDO" minOccurs="0" maxOccurs="unbounded"/>
 <element name="processControl" type="ns3:ProcessControl"/>
 </sequence>
 </complexType>
 </element>
 <element name="processEmployeesSDOResponse">
 <complexType>
 <sequence>
 <element name="result" type="ns0:EmployeesSDO" minOccurs="0" maxOccurs="unbounded"/>
 </sequence>
 </complexType>
 </element>
 <element name="processCSEmployeesSDO">
 <complexType>
 <sequence>
 <element name="processData" type="ns3:ProcessData"/>
 <element name="processControl" type="ns3:ProcessControl"/>
 </sequence>
 </complexType>
 </element>
 <element name="processCSEmployeesSDOResponse">
 <complexType>
 <sequence>
 <element name="result" type="ns3:ProcessData"/>
 </sequence>
 </complexType>
 </element>
 <!-- END SDO Elements -->

This is an extract for the wsdl message definitions within the HrSessionEJBBeanWS.wsdl:

<!-- BEGIN SDO Messages -->
 <wsdl:message name="HrSessionEJBBeanWS_getEmployeesSDO">
 <wsdl:part name="parameters" element="types:getEmployeesSDO"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_getEmployeesSDOResponse">
 <wsdl:part name="parameters" element="types:getEmployeesSDOResponse"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_createEmployeesSDO">
 <wsdl:part name="parameters" element="types:createEmployeesSDO"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_createEmployeesSDOResponse">
 <wsdl:part name="parameters" element="types:createEmployeesSDOResponse"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_updateEmployeesSDO">
 <wsdl:part name="parameters" element="types:updateEmployeesSDO"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_updateEmployeesSDOResponse">
 <wsdl:part name="parameters" element="types:updateEmployeesSDOResponse"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_deleteEmployeesSDO">
 <wsdl:part name="parameters" element="types:deleteEmployeesSDO"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_deleteEmployeesSDOResponse">
 <wsdl:part name="parameters" element="types:deleteEmployeesSDOResponse"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_mergeEmployeesSDO">
 <wsdl:part name="parameters" element="types:mergeEmployeesSDO"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_mergeEmployeesSDOResponse">
 <wsdl:part name="parameters" element="types:mergeEmployeesSDOResponse"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_findEmployeesSDO">
 <wsdl:part name="parameters" element="types:findEmployeesSDO"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_findEmployeesSDOResponse">
 <wsdl:part name="parameters" element="types:findEmployeesSDOResponse"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_processEmployeesSDO">
 <wsdl:part name="parameters" element="types:processEmployeesSDO"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_processEmployeesSDOResponse">
 <wsdl:part name="parameters" element="types:processEmployeesSDOResponse"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_processCSEmployeesSDO">
 <wsdl:part name="parameters" element="types:processCSEmployeesSDO"/>
 </wsdl:message>
 <wsdl:message name="HrSessionEJBBeanWS_processCSEmployeesSDOResponse">
 <wsdl:part name="parameters" element="types:processCSEmployeesSDOResponse"/>
 </wsdl:message>
 <!-- END SDO Messages -->

The wsdl operation defintions for the Employees entity:

<!-- BEGIN SDO Operations -->
 <wsdl:operation name="getEmployeesSDO">
 <wsdl:input message="tns:HrSessionEJBBeanWS_getEmployeesSDO"/>
 <wsdl:output message="tns:HrSessionEJBBeanWS_getEmployeesSDOResponse"/>
 <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
 </wsdl:operation>
 <wsdl:operation name="createEmployeesSDO">
 <wsdl:input message="tns:HrSessionEJBBeanWS_createEmployeesSDO"/>
 <wsdl:output message="tns:HrSessionEJBBeanWS_createEmployeesSDOResponse"/>
 <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
 </wsdl:operation>
 <wsdl:operation name="updateEmployeesSDO">
 <wsdl:input message="tns:HrSessionEJBBeanWS_updateEmployeesSDO"/>
 <wsdl:output message="tns:HrSessionEJBBeanWS_updateEmployeesSDOResponse"/>
 <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
 </wsdl:operation>
 <wsdl:operation name="deleteEmployeesSDO">
 <wsdl:input message="tns:HrSessionEJBBeanWS_deleteEmployeesSDO"/>
 <wsdl:output message="tns:HrSessionEJBBeanWS_deleteEmployeesSDOResponse"/>
 <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
 </wsdl:operation>
 <wsdl:operation name="mergeEmployeesSDO">
 <wsdl:input message="tns:HrSessionEJBBeanWS_mergeEmployeesSDO"/>
 <wsdl:output message="tns:HrSessionEJBBeanWS_mergeEmployeesSDOResponse"/>
 <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
 </wsdl:operation>
 <wsdl:operation name="findEmployeesSDO">
 <wsdl:input message="tns:HrSessionEJBBeanWS_findEmployeesSDO"/>
 <wsdl:output message="tns:HrSessionEJBBeanWS_findEmployeesSDOResponse"/>
 <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
 </wsdl:operation>
 <wsdl:operation name="processEmployeesSDO">
 <wsdl:input message="tns:HrSessionEJBBeanWS_processEmployeesSDO"/>
 <wsdl:output message="tns:HrSessionEJBBeanWS_processEmployeesSDOResponse"/>
 <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
 </wsdl:operation>
 <wsdl:operation name="processCSEmployeesSDO">
 <wsdl:input message="tns:HrSessionEJBBeanWS_processCSEmployeesSDO"/>
 <wsdl:output message="tns:HrSessionEJBBeanWS_processCSEmployeesSDOResponse"/>
 <wsdl:fault name="ServiceException" message="errors:ServiceException"/>
 </wsdl:operation>
<!-- END SDO Operations -->

And finally the wsdl operation bindings:

<!-- BEGIN SDO Bindings -->
 <wsdl:operation name="getEmployeesSDO">
 <soap:operation soapAction="/nl.amis.sdo.jpa.services/getEmployeesSDO"/>
 <wsdl:input>
 <soap:body use="literal"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body use="literal"/>
 </wsdl:output>
 <wsdl:fault name="ServiceException">
 <soap:fault name="ServiceException" use="literal"/>
 </wsdl:fault>
 </wsdl:operation>
 <wsdl:operation name="createEmployeesSDO">
 <soap:operation soapAction="/nl.amis.sdo.jpa.services/createEmployeesSDO"/>
 <wsdl:input>
 <soap:body use="literal"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body use="literal"/>
 </wsdl:output>
 <wsdl:fault name="ServiceException">
 <soap:fault name="ServiceException" use="literal"/>
 </wsdl:fault>
 </wsdl:operation>
 <wsdl:operation name="updateEmployeesSDO">
 <soap:operation soapAction="/nl.amis.sdo.jpa.services/updateEmployeesSDO"/>
 <wsdl:input>
 <soap:body use="literal"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body use="literal"/>
 </wsdl:output>
 <wsdl:fault name="ServiceException">
 <soap:fault name="ServiceException" use="literal"/>
 </wsdl:fault>
 </wsdl:operation>
 <wsdl:operation name="deleteEmployeesSDO">
 <soap:operation soapAction="/nl.amis.sdo.jpa.services/deleteEmployeesSDO"/>
 <wsdl:input>
 <soap:body use="literal"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body use="literal"/>
 </wsdl:output>
 <wsdl:fault name="ServiceException">
 <soap:fault name="ServiceException" use="literal"/>
 </wsdl:fault>
 </wsdl:operation>
 <wsdl:operation name="mergeEmployeesSDO">
 <soap:operation soapAction="/nl.amis.sdo.jpa.services/mergeEmployeesSDO"/>
 <wsdl:input>
 <soap:body use="literal"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body use="literal"/>
 </wsdl:output>
 <wsdl:fault name="ServiceException">
 <soap:fault name="ServiceException" use="literal"/>
 </wsdl:fault>
 </wsdl:operation>
 <wsdl:operation name="findEmployeesSDO">
 <soap:operation soapAction="/nl.amis.sdo.jpa.services/findEmployeesSDO"/>
 <wsdl:input>
 <soap:body use="literal"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body use="literal"/>
 </wsdl:output>
 <wsdl:fault name="ServiceException">
 <soap:fault name="ServiceException" use="literal"/>
 </wsdl:fault>
 </wsdl:operation>
 <wsdl:operation name="processEmployeesSDO">
 <soap:operation soapAction="/nl.amis.sdo.jpa.services/processEmployeesSDO"/>
 <wsdl:input>
 <soap:body use="literal"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body use="literal"/>
 </wsdl:output>
 <wsdl:fault name="ServiceException">
 <soap:fault name="ServiceException" use="literal"/>
 </wsdl:fault>
 </wsdl:operation>
 <wsdl:operation name="processCSEmployeesSDO">
 <soap:operation soapAction="/nl.amis.sdo.jpa.services/processCSEmployeesSDO"/>
 <wsdl:input>
 <soap:body use="literal"/>
 </wsdl:input>
 <wsdl:output>
 <soap:body use="literal"/>
 </wsdl:output>
 <wsdl:fault name="ServiceException">
 <soap:fault name="ServiceException" use="literal"/>
 </wsdl:fault>
 </wsdl:operation>
 <!-- END SDO Bindings -->

The complete WSDL definition can be found here: https://raw.github.com/dabla/ejb-jpa2-sdo-service/master/ModelSDO/src/nl/amis/sdo/jpa/services/HrSessionEJBBeanWS.wsdl
Also mind that I putted comments around the definitions for one Entity so you can easily copy and paste it and perform search/replace on it.  I did this with Notepad++, which is a great tool by the way.

SCA

The composite will look like the original one, except that the HrEjbSDOService reference will have other methods as those have been changed as explained above.

BPEL

Below you can see the modified BPEL which binds with employee sdo variable.

When you double click on the “BindEmployeesEntity” element, you shall see the following definition:

As explained above the Key QName corresponds with the annotation definition found in the XSD of the corresponding SDO (*).

Here is the source code of the BPEL component:

<?xml version = "1.0" encoding = "UTF-8" ?>
<!--
//////////////////////////////////////////////////////////////////////////
 Oracle JDeveloper BPEL Designer

 Created: Tue Aug 07 19:52:49 CEST 2012
 Author: admin
 Type: BPEL 2.0 Process
 Purpose: One Way BPEL Process
//////////////////////////////////////////////////////////////////////////
-->
<process name="BPELSdoService"
 targetNamespace="http://xmlns.oracle.com/EjbSdoServiceSOA/SoaSDOEjbService/BPELSdoService"
 xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
 xmlns:client="http://xmlns.oracle.com/EjbSdoServiceSOA/SoaSDOEjbService/BPELSdoService"
 xmlns:ora="http://schemas.oracle.com/xpath/extension"
 xmlns:bpel="http://docs.oasis-open.org/wsbpel/2.0/process/executable"
 xmlns:ns1="/nl.amis.sdo.jpa.services/"
 xmlns:ns2="/nl.amis.sdo.jpa.entities/"
 xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
 xmlns:bpws="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
 xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20"
 xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc"
 xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue"
 xmlns:hwf="http://xmlns.oracle.com/bpel/workflow/xpath"
 xmlns:ids="http://xmlns.oracle.com/bpel/services/IdentityService/xpath"
 xmlns:bpm="http://xmlns.oracle.com/bpmn20/extensions"
 xmlns:xdk="http://schemas.oracle.com/bpel/extension/xpath/function/xdk"
 xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions"
 xmlns:ldap="http://schemas.oracle.com/xpath/extension/ldap">

<!--import namespace="http://xmlns.oracle.com/EjbSdoServiceSOA/SoaSDOEjbService/BPELSdoService" location="BPELSdoService.wsdl" importType="http://schemas.xmlsoap.org/wsdl/"/-->

<!--
//////////////////////////////////////////////////////////////////////////
 PARTNERLINKS
 List of services participating in this BPEL process
//////////////////////////////////////////////////////////////////////////
 -->
 <partnerLinks>
 <!--
 The 'client' role represents the requester of this service. It is
 used for callback. The location and correlation information associated
 with the client role are automatically set using WS-Addressing.
 -->
 <partnerLink name="bpelsdoservice_client"
 partnerLinkType="client:BPELSdoService"
 myRole="BPELSdoServiceProvider"/>
 <partnerLink name="HrEjbSDOService" partnerLinkType="ns1:HrEjbSDOService"
 partnerRole="HrSessionEJBBeanWS"/>
 </partnerLinks>
 <!--
//////////////////////////////////////////////////////////////////////////
 VARIABLES
 List of messages and XML documents used within this BPEL process
//////////////////////////////////////////////////////////////////////////
 -->
 <variables>
 <!-- Reference to the message passed as input during initiation -->
 <variable name="inputVariable"
 messageType="client:BPELSdoServiceRequestMessage"/>
 <variable name="employeesEV" element="ns2:employeesSDO"
 bpelx:entity.si="HrEjbSDOService"/>
 </variables>
 <!--
//////////////////////////////////////////////////////////////////////////
 ORCHESTRATION LOGIC
 Set of activities coordinating the flow of messages across the
 services integrated within this business process
//////////////////////////////////////////////////////////////////////////
 -->
 <sequence name="main">
 <!-- Receive input from requestor. (Note: This maps to operation defined in BPELSdoService.wsdl) -->
 <receive name="receiveInput" partnerLink="bpelsdoservice_client"
 portType="client:BPELSdoService" operation="process"
 variable="inputVariable" createInstance="yes"/>
 <bpelx:bindEntity name="BindEmployeesEntity" variable="employeesEV">
 <bpelx:key keyname="ns2:employeeId">
string(bpws:getVariableData('inputVariable','payload','/client:process/client:input'))
</bpelx:key>
 </bpelx:bindEntity>
 </sequence>
</process>

IMPORTANT:  Do not make the same mistake I did and do not forget to redeploy the sdoHrInterface profile from the ModelSDO project.  Once the jar file is being redeployed, copy it to the SCA-INF/lib directory of the SoaSDOEjbService project!  This will avoid exceptions like this one:

Binding Component is unable to locate operation findEmployeesSDO for java service
EjbSdoService-HrSessionEJB#nl.amis.sdo.jpa.services.HrSessionEJB.

Also notice that I have changed the xmls namespace of the BPEL component back to http://schemas.xmlsoap.org/ws/2003/03/business-process/ as the new BPEL 2.0 one (namely: http://docs.oasis-open.org/wsbpel/2.0/process/executable) doesn’t support all the Oracle BPEL extensions like BindEntity etc. which we just need in this case.  The import element has also been commented out.

Deploy and test

Just deploy and run the test class named HrSessionEJBClientSDO in the TestEJB project.  You should see something similar in the console as shown in the picture below.

I also modified the original SoapUI project and added a TestSuite which tests the SDO through SOAP.  I’ve successfully managed to create, get, find and delete an employee through the SDO.

Here you’ll find the modified SoaSDOEjbService project which does the binding with the EmployeesSDO:

https://github.com/dabla/ejb-jpa2-sdo-service-soa

When you test the composite, you’ll need to pass the employeeId to the input parameter of the composite like shown bellow.

From now on we have an alternative to ADF-BC based SDO’s in combination with the Oracle BPEL extensions🙂

Tagged , , , , , , ,

Exposing an EJB SDO Service Interface as a SOAP WebService

Introduction

This example is based on the one posted by Edwin Biemond at: http://biemond.blogspot.be/2012/08/generating-ejb-sdo-service-interface.html

To purpose of this example was to be able to expose the EJB based SDO example from above through SOAP.

To achieve this I had to do the following steps.

Add a WAR deployment profile

Right click on the ‘ModelSDO’ project, choose ‘Project Properties’.

Go to ‘Deployment’ and create a new Deployment Profile by clicking on ‘New…’.

In the Create Deployment Profile choose ‘WAR File’ as Achive Type and name it for example ‘SdoEjbService’, then click ‘OK’ to confirm.

Alter EAR deployment profile

Before we continue with the web archive part, we will first alter the EAR deployment profile so that the ‘ModelSDO’ EJB and WAR gets well deployed.

To achieve this click on the context menu right of the ‘EjbSdoService’ application and select ‘Application Properties…’.

There you’ll see a Deployment Profile named ‘ejbsdoservice (EAR File)’, select it and click on ‘Edit…’.

Under ‘Application Assembly’, make sure ‘hrSdoEjbService’ and ‘SdoEjbService’ is selected and click on ‘OK’.

This will allow the assembling of the EJB and WAR within the EAR.  Also click on ‘OK’ when you are returned to the ‘Application Properties’ popup.

Add Web deployment descriptor

Now that the ModelSDO is WAR aware, we need to add a web deployment descriptor (e.g. web.xml). To achieve this do the following:

Right click on the ‘ModelSDO’ project, select ‘New…’ from the context menu.

In the tab ‘Current Project Technologies’, make sure the tree node ‘Categories’ is set to ‘General’ and ‘Deployment Descriptors’.

There you need to select the item labeled ‘Java EE Deployment Descriptor’ and click on ‘OK’. In the dialog ‘Create Java EE Deployment Descriptor’, make sure you select ‘web.xml’ in step 1 and click on ‘Next >’.

Set the deployment descriptor version to 2.5 and hit ‘Next >’.

In the last step just click on ‘Finish’.

Now you’ll notice that the ‘ModelSDO’ project has a third directory named ‘Web Content’ containing a ‘WEB-INF’ directory with 2 files, namely ‘weblogic.xml’ and the just created deployment descriptor named ‘web.xml’.

Now click on the source mode of the web.xml file and copy/paste the following content in it:

</pre>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 version="2.5">
 <!-- https://forums.oracle.com/forums/thread.jspa?threadID=987232 -->
 <servlet>
 <display-name>nl.amis.sdo.jpa.services.HrSessionEJBBeanWSForward</display-name>
 <servlet-name>nl.amis.sdo.jpa.services.HrSessionEJBBeanWSForward</servlet-name><!-- name of the servlet mapping to HrSessionEJBBean WebService -->
 <servlet-class>oracle.j2ee.ws.server.WSForwardServlet</servlet-class>
 <init-param>
 <param-name>to</param-name>
 <param-value>/HrSessionEJBBeanWS</param-value><!-- servlet path mapping to HrSessionEJBBean WebService -->
 </init-param>
 </servlet>
 <servlet>
 <servlet-name>nl.amis.sdo.jpa.services.HrSessionEJBBean</servlet-name><!-- name of the servlet mapping to HrSessionEJBBean WebService -->
 <servlet-class>oracle.j2ee.ws.server.provider.ProviderServlet</servlet-class>
 <init-param>
 <param-name>Oracle.JAX-WS.EjbLink</param-name>
 <param-value>ejb/HrSessionEJB</param-value><!-- link to the ejb HrSessionEJB -->
 </init-param>
 <init-param>
 <param-name>Oracle.JAX-WS.ServiceEndpointBean</param-name>
 <param-value>nl.amis.sdo.jpa.services.HrSessionEJBBean</param-value><!-- fully qualified Java name of the HrSessionEJB implementation -->
 </init-param>
 <load-on-startup>1</load-on-startup>
 </servlet>
 <servlet-mapping>
 <servlet-name>nl.amis.sdo.jpa.services.HrSessionEJBBean</servlet-name>
 <url-pattern>/HrSessionEJBBeanWS</url-pattern><!-- servlet path mapping to HrSessionEJBBean WebService -->
 </servlet-mapping>
 <servlet-mapping>
 <servlet-name>nl.amis.sdo.jpa.services.HrSessionEJBBeanWSForward</servlet-name>
 <url-pattern>/HrSessionEJBBeanWS/secure</url-pattern><!-- secured servlet path mapping to HrSessionEJBBean WebService -->
 </servlet-mapping>
 <login-config>
 <auth-method>BASIC</auth-method>
 </login-config>
 <security-role>
 <role-name>Admin</role-name>
 </security-role>
 <security-constraint>
 <web-resource-collection>
 <web-resource-name>nl.amis.sdo.jpa.services.HrSessionEJBBeanWS</web-resource-name>
 <url-pattern>/HrSessionEJBBeanWS/secure</url-pattern><!-- secured servlet path mapping to HrSessionEJBBean WebService -->
 </web-resource-collection>
 <auth-constraint>
 <role-name>Admin</role-name>
 </auth-constraint>
 <user-data-constraint>
 <transport-guarantee>CONFIDENTIAL</transport-guarantee>
 </user-data-constraint>
 </security-constraint>
 <ejb-ref><!-- define EJB reference in WAR for use above in ProviderServlet definition -->
 <ejb-ref-name>ejb/HrSessionEJB</ejb-ref-name>
 <ejb-ref-type>Session</ejb-ref-type>
 <remote>nl.amis.sdo.jpa.services.HrSessionEJB</remote>
 <ejb-link>HrSessionEJB</ejb-link>
 </ejb-ref>
</web-app>
<pre>

If you’re wondering how I defined the above web.xml file, I just took the content of a web.xml from an ADF-BC SDO generated WAR and modified it so that it matched my web service definition.

Add and modify oracle specific web service XML definitions

From that same generated ADF-BC SDO WAR file, I also copied the following files to the ModelSDO project directory under ‘public_html\WEB-INF’ (shown as Web Content/WEB-INF in JDeveloper):

  • oracle-webservices.xml
  • standard-webservices.xml

I also modified the content of both files so that they matched the definitions of my web service.

For oracle-webservices.xml:

</pre>
<?xml version="1.0" encoding="UTF-8"?>
<oracle-webservices xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="http://xmlns.oracle.com/oracleas/schema/11/oracle-webservices-11_1.xsd"
 schema-major-version="11" schema-minor-version="1">
 <context-root>EjbSdoService-ModelSDO-context-root</context-root><!-- context root of the WAR -->
 <webservice-description name="{/nl.amis.sdo.jpa.services/}HrSessionEJBBeanWS"><!-- fully qualified WebService name -->
 <expose-wsdl>true</expose-wsdl>
 <expose-testpage>true</expose-testpage>
 <schema-file-mappings>
 <schema-file-mapping advertisedName="/nl/amis/sdo/jpa/entities/EmployeesSDO.xsd"
 path="/nl/amis/sdo/jpa/entities/EmployeesSDO.xsd"/><!-- full path (starting form WEB-INF/wsdl) to the xsd defintion (mind entities) -->
 <schema-file-mapping advertisedName="/nl/amis/sdo/jpa/entities/DepartmentsSDO.xsd"
 path="/nl/amis/sdo/jpa/entities/DepartmentsSDO.xsd"/><!-- full path (starting form WEB-INF/wsdl) to the xsd defintion (mind entities) -->
 <schema-file-mapping advertisedName="/nl/amis/sdo/jpa/services/HrSessionEJBBeanWS.xsd"
 path="/nl/amis/sdo/jpa/services/HrSessionEJBBeanWS.xsd"/><!-- full path (starting form WEB-INF/wsdl) to the xsd defintion (mind services) -->
 <schema-file-mapping advertisedName="/xml/datagraph.xsd"
 path="/xml/datagraph.xsd"/><!-- full path (starting form WEB-INF/wsdl) to the commonj SDO xsd defintions -->
 <schema-file-mapping advertisedName="/xml/sdoModel.xsd"
 path="/xml/sdoModel.xsd"/><!-- full path (starting form WEB-INF/wsdl) to the commonj SDO xsd defintions -->
 <schema-file-mapping advertisedName="/xml/sdoJava.xsd"
 path="/xml/sdoJava.xsd"/><!-- full path (starting form WEB-INF/wsdl) to the commonj SDO xsd defintions -->
 <schema-file-mapping advertisedName="/xml/sdoXML.xsd"
 path="/xml/sdoXML.xsd"/><!-- full path (starting form WEB-INF/wsdl) to the commonj SDO xsd defintions -->
 </schema-file-mappings>
 <port-component name="HrSessionEJBBeanWS" enabled="true"
 schemaValidateInput="false">
 <mtom-support threshold="0">false</mtom-support>
 <endpoint-address-uri>/HrSessionEJBBeanWS</endpoint-address-uri><!-- servlet path mapping to HrSessionEJBBean WebService -->
 </port-component>
 <enable-mex>true</enable-mex>
 </webservice-description>
</oracle-webservices>
<pre>

Mind the content-root element (jbSdoService-ModelSDO-context-root), it the same as the one proposed by default when we created the WAR deployment profile.

For standard-webservices.xml:

</pre>
<?xml version="1.0" encoding="UTF-8"?>
<webservices xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/javaee_web_services_1_2.xsd" version="1.2">
 <webservice-description>
 <webservice-description-name>{/nl.amis.sdo.jpa.services/}HrSessionEJBBeanWS</webservice-description-name><!-- fully qualified WebService name -->
 <wsdl-file>WEB-INF/wsdl/nl/amis/sdo/jpa/services/HrSessionEJBBeanWS.wsdl</wsdl-file><!-- location of the WSDL file in our WAR project -->
 <jaxrpc-mapping-file/>
 <port-component>
 <port-component-name>HrSessionEJBBeanWS</port-component-name><!-- corresponds to the name defintion found in HrSessionEJBBeanWS.wsdl -->
 <wsdl-service xmlns:ns0="/nl.amis.sdo.jpa.services/">ns0:HrSessionEJBBeanWS</wsdl-service><!-- namespace ns0 corresponds to the targetNamespace defintion found in HrSessionEJBBeanWS.wsdl -->
 <wsdl-port xmlns:ns1="/nl.amis.sdo.jpa.services/">ns1:HrSessionEJBBeanWSSoapHttpPort</wsdl-port><!-- namespace ns1 corresponds to the targetNamespace defintion found in HrSessionEJBBeanWS.wsdl -->
 <enable-mtom>false</enable-mtom>
 <service-endpoint-interface>nl.amis.sdo.jpa.services.HrSessionEJB</service-endpoint-interface><!-- corresponds to the Java remote EJB interface -->
 <service-impl-bean>
 <servlet-link>nl.amis.sdo.jpa.services.HrSessionEJBBean</servlet-link><!-- corresponds to the Java EJB implementation name -->
 </service-impl-bean>
 </port-component>
 </webservice-description>
</webservices>
<pre>

Mind that the element ‘wsdl-file’ points to the ‘WEB-INF/wsdl’-directory, which doesn’t exist yet. This will be done in the next step.

Add WSDL and XSD defintions

First we need to copy the WSDL and XSD-files to the WEB-INF/wsdl directory, to do this we create a directory ‘wsdl’ under WEB-INF within JDeveloper.

Once the directory create we’ll copy the WSDL and XSD-files from the ‘src’ directory of the ModelSDO project to the ‘WEB-INF/wsdl’ directory,
make sure the directory structure keeps intact. It should look like the following screenshot.

UPDATE: You’ll notice that the wsdl and xsd-files aren’t present anymore within the Web Content/WEB-INF/wsdl directory in the GitHub project repository.  Those are dynamically added from the source path at deployment time.  To achieve this I modified the Web Deployment Profile.  This has the main advantage that those files have only to be maintained at one location.

I also copied the SDO xsd specifications (origins from the commonj sdo library) from the generated ADF-BC SDO WAR file located under WEB-INF/wsdl/xml into our project.

Now the project should look like the following screenshot.

I didn’t copy the ADF-BC xsd definitions as we don’t use ADF-BC in our project.

Deploy and test

Now the best part is the deployment of our EjbSdoService application and see if it is also exposed as a SOAP WebService so that we can invoke it from SoapUI.

Once deployed, login to your weblogic console, for example at http://localhost:7001/console, and go to your deployments.  There select the ‘ejbsdoservice’ deployment.

You’ll notice that there aren’t any webservices listed although it’s there, maybe I forgot to add something to make it visible from the console?

Just enter the following url which will redirect you to the test page of the webservice:

http://localhost:7001/EjbSdoService-ModelSDO-context-root/HrSessionEJBBeanWS

If at runtime you receive the following weird exception (EclipseLink-45010) while invoking the webservice, just go to the following url and do as explained there: https://forums.oracle.com/forums/thread.jspa?threadID=987232:


Exception Description: A type could not be found for interface class [nl.amis.sdo.jpa.entities.EmployeesSDO]. Please make sure that the type has been defined. In addition, the interface classloader should be a member of the helper context classloader hierarchy: it appears as if this is [false].

The whole JDeveloper project can be found on GitHub: https://github.com/dabla/ejb-sdo-service

It is also the goal to mavenize this and put some JUnit tests with it, so updates on this post will follow.

Tagged , , , , , ,

DIY FreeNAS based system

Introduction

This time I won’t be writing about software related stuff but about building a Network-Attached Storage (e.g. NAS) based on FreeNAS.  A family member asked me if I would be able to build a custom NAS system for him.  As some years have already passed by since  my last PC build, I wasn’t up-to-date with the current available hardware and I didn’t have any knowledge of NAS setups what so ever.

The requirement were:

  • the data should be stored redundantly;
  • it should be easily recoverable in case of failure;
  • it should backup data to an external usb drive;
  • the system should be easy to maintain;
  • the system should have a low power consumption;
  • the system should be quiet;
  • there should be a notion of users and permissions with dedicated folder;
  • it should be able to recover unwanted modifications on data;
  • and if possible run a mail server on top of it.

Thanks to the help of some people, and especially CiPHER, at the tweakers.net forum, I was able to determine the setup I was going to assemble.

Components inventory

NAS PC Components

Here is the list of the components shown above:

Assembling the compontents

Here’s how I proceeded for assembling the NAS components:

  1. Open the side panel of the cooler master.
  2. Mount the 4 metal hex nuts, which are supplied with the mini-tower, so that they match the Mini ITX Form Factor on which the motherboard will be mounted.
  3. Put the I/O Panel Shield on the back of the motherboard and fix it on the case.
  4. Now we’ll put the 2 memory modules in the memory slots.
  5. Wire the picoPSU peripheral extension cable to the picoPSU.
  6. Wire the picoPSU on the ATX power connectors (24-pin and 4-pin connector) of the motherboard.
  7. Wire the cables of the case regarding power led, HD led, power switch and reset switch to the motherboard.
  8. Wire the front panel USB cable of the case to the motherboard.
  9. Wire the HD audio interface cable of the case to the motherboard.
  10. Mount the SSD in the floppy drive bay.
  11. Mount the 3 HD’s in the hard drive bays.

The result of it should look like the picture shown below.

Assembled PC Compents

Running rsync via cron job

One requirement was that a backup should be made from the ZFS pool offsite to an external USB drive. To achieve that I wrote a script based on an example that I found on the freenas forum.

  1. From what I understood on a blog about Freenas is that it loads all it’s stuff from the “/conf/base”-directory in a RAM disk and maps it to the standard Unix installation structure. This means that every modification you made will be lost after a reboot or shutdown. To make those modifications permanent, we have to mount the volume so that we can write on it. To do that execute the following in the shell:
    mount -uw /
  2. Now we are going to write a shell script containing the logic for rsync-ing the ZFS pool to an external USB drive:
    nano /conf/base/var/backup.sh
  3. Once in nano, or any other editor you whish to use, enter the following:
    #!/bin/bash
    partition=/dev/$1
    origin=/mnt/$2
    target=/mnt/backup
    
    backup() {
    	if [ -e ${partition} ]; then
    		/bin/mkdir -p ${target}
    		/bin/chmod 777 ${target}
    		/usr/bin/logger "Mounting USB Device named ${partition} to ${target}..."
    		/sbin/mount -t ext2fs ${partition} ${target}
    		/usr/bin/logger "Mounted USB Device named ${partition} to ${target}"
    		/usr/bin/logger "Rsyncing ${origin} to ${target}..."
    		rsync -av --progress ${origin} ${target}
    		/usr/bin/logger "Unmounting USB Device named ${partition} from ${target}..."
    		umount ${target}
    		/usr/bin/logger "Unmounted USB Device named ${partition} from ${target}"
    		/bin/rm -r ${target}
    	else
    		/usr/bin/logger "USB Device named ${device} not present"
    	fi
    }
    
    backup;
    
  4. Make sure the script is executable:
    chmod 777 /conf/base/var/backup.sh
  5. Set the base volume back to read-only:
    mount -ur /
  6. Exit the shell by typing “exit” in the shell and hit the reboot option.

Once the FreeNAS system is rebooted, you should see via the shell that the script is located under /var/backup.sh. Now let’s create a cron job via the web interface of FreeNAS. As you’ll could have noticed when typing the script, there are 2 arguments:

  • the first argument specifies the device name of the usb device (without the prefix /dev)
  • the second argument specifies the name of the ZFS pool (without the prefix /mnt)

Let’s consider as an example that the full path to the device would be “/dev/da1s1” and the full path to the ZFS pool would be “/mnt/dablomatique”, the script have to be executed as follow:

/var/backup.sh da1s1 dablomatique

That’s it for the moment. If there are any suggestions, they are always welcome.

Building collapsed EAR through Maven for Weblogic & Tomcat with OpenEJB aka TomEE

Introduction

For this tutorial I had the challenge to deploy the same Java enterprise application (e.g. EAR-file) on Oracle Weblogic as well as on Apache Tomcat.

First of all you have to know that Tomcat isn’t an application server.  It also doesn’t support the deployment of EAR-files, which is logical considering the first statement.  Luckily, since JEE6, there is the possibility of the collapsed EAR technique (see http://openejb.apache.org/collapsed-ear.html), which consist of repackaging the EAR-file into WAR-file which is deployable on Tomcat.  Tomcat doesn’t also support Enterprise Java Beans out of the box, so that’s were TomEE comes to the rescue. TomEE is a project which simplifies the usage of OpenEJB on Tomcat.

In this article I will mainly focus on Tomcat and less on Weblogic because it was more challeging to make it run on Tomcat.  The result is that the application will run on both servers.

The application uses Java Persistence Api 1.0 with Eclipse Link to connect to the database.  This is all exposed through EJB’s.  There is also the need to talk to a JMS Queue and process the messages via a Message Driven Bean.

The UI is done with Java Server Faces 2.  The application has of course to be unit tested.

Used technologies

The application uses several JEE technologies, namely:

  • JPA or Java Persistence API 1.0 with Eclipse Link 1.1.0 as provider.
  • EJB or Enterprise Java Beans 3.0 with OpenEJB 3.1.4 as provider.
  • Bean Validation API 1.0 with Hibernate Validator 4.0.2 as provider.
  • JMS or Java Messaging Service with ActiveMQ 5.2 as provider.
  • JSF or Java Server Faces 2.0 with the Glassfish reference implemenation as provider.
  • JAX-WS or Java API for XML Web Services with Glassfish Metro and Apache CXF as possible providers.

Configuration in 10 steps

  1. Install Tomcat 6.0.35.
  2. Copy ojdbc14-10.2.0.4.0.jar to %TOMCAT_INSTALL_DIR%/lib.
  3. Copy eclipselink-1.1.0.jar to %TOMCAT_INSTALL_DIR%/lib.
  4. Copy validation-api-1.0.0.GA.jar to %TOMCAT_INSTALL_DIR%/lib.
  5. Copy hibernate-validator-4.0.2.GA.jar to %TOMCAT_INSTALL_DIR%/lib.
  6. Copy slf4j-api-1.6.1.jar to %TOMCAT_INSTALL_DIR%/lib.
  7. Copy openejb.war to %TOMCAT_INSTALL_DIR%/webapps.
  8. Start Tomcat and once up-and-running, go to the following url with your browser (if Tomcat is running on localhost with port 8080, will vary depending on your installation): http://localhost:8080/openejb/installer.
  9. Click on the ‘install’-button on the webpage, once installed, stop Tomcat.
  10. Go to the %TOMCAT_INSTALL_DIR%/config directory and edit the the openejb.xml file. Under the Resource-element named “My JMS Resource Adapter” and before the Connector-element named “My JMS Connection Factory”, add the following resources in between as defined below:
<Resource id="jdbc/tomee-maven-demo-ds" type="DataSource">
  JdbcDriver oracle.jdbc.xa.client.OracleXADataSource
  JdbcUrl jdbc:oracle:thin:@localhost:1521:XE
  UserName scott
  Password scott
  JtaManaged true
</Resource>

<Resource id="jms/tomee-maven-demo-cf" type="javax.jms.ConnectionFactory">
  ResourceAdapter My JMS Resource Adapter
</Resource>

<Resource id="jms/tomee-maven-demo-q" type="javax.jms.Queue" />

Project setup

The project is divided into 4 different modules.

  1. The jar module consists of  entity classes, the domain interface and service interface.
  2. The ejb module contains the domain EJB’s storing the entities through JPA and eclipse link and the MDB’s processing the messages stored on the queue.
  3. The war module contains the JSF 2 related stuff needed for the UI.
  4. The ear module packages all the modules for deployment on an application server.

For clarification: I wanted to put the persistence.xml and orm.xml files inside the jar-file containing the EJB’s as those are the classes using the JPA entity manager.  Unfortunately it lead to class loading issues in Weblogic as the EJB jar is packaged directly under the EAR file. The entity classes are located under the APP-INF/lib (shared lib) directory within the ear which resulted in my entity classes not being found (e.g. ClassNotFoundException).  I’ve tried adding a reference to the jar containing the entity classes with the section within the persistence.xml file, but no avail. That’s why I putted those XML-files in the jar file containing the entity classes instead of the EJB jar.

Purpose

The purpose of this demo application is to develop an asynchronous webservice named MessageService.  The webservice puts the given message on a queue through an EJB called MessageMDBSender.  There is a Message Driven Bean named MessageMDB which will process any message posted on the queue and store them in the database through an EJB called MessageEJB.  That EJB uses JPA 1.0 with Eclipse Link to store the message into the database.  If the creation of the given message is successful, the webservice will send a callback to the client who send the initial request.

I’ve also added a soapUI project to allow the testing of the deployed asynchronous webservice on Tomcat

The code that is used to develop the asynchronous webservice is based on the example posted by Biemond, except I adapted the code to make it independent of the used webservice stack.

This means that the same code will work on Metro as well as on CXF, which is necessary as weblogic uses Metro and OpenEJB uses CXF. It also works with the Oracle SOA Suite for that manner.

Beside that I also wrote a class named CXFServlet in the test package of the war project. This class is also packaged with the war when building for Tomcat as I couldn’t figure out how to make the CXF webservices work out of the box with OpenEJB.  It seems that the webservices are deployed under the root of the Tomcat installation and not under the context root of the deployed web application.  If someone could tell me how to solve this issue that would we great as it would make the demo even simpler. Another problem that I encountered with OpenEjb and Tomcat is that the resource injection through env-entries in the ejb-jar.xml isn’t working. The same ejb-jar.xml file injects the env-entries correctly on Weblogic so I suspect there might be a bug there in the 3.1.4 release of OpenEJB. The injection also fails with unit tests.

To build the project for Weblogic, just type mvn clean install. Then deploy the generated ear-file to the application server.

To build the project for Tomcat, just type mvn clean install -Ptomcat. Then copy the generated war-file to the webapps directory of the Tomcat installation directory.

You can find the complete project on https://github.com/dabla/tomee-maven-demo.

Tagged , , , , , , , , , , ,

Building and testing ADF applications with Maven, JSFUnit, Arquillian and Embedded Glassfish

tomcat

Some time ago I have been playing with Java Server Faces 2.0 (e.g. JSF 2) and JSFUnit in combination with Arquillian and Embedded Glassfish as a Proof Of Concept for unit testing JSF applications.

As our applications are being developped with the Oracle ADF framework, I was wondering if it would be possible to do the same with ADF based applications.  The purpose is to build ADF applications with Maven, which is not that hard, but also test it on an Embedded Glassfish, which is quite challenging.  Once this is working, we could use Jenkins as our continuous integration platform.

The first challenge was to determine the required ADF libraries.  As those libraries are defined as a shared library in Weblogic, I had to determine which where needed to make the ADF application run on Glassfish.  To do this, I added the libraries one by one until the ClassNotFoundExceptions were gone.

Then I made a script (e.g. bat-file) which installs all those libraries in my local Maven repository.  I also made some parent POM’s so I could bundle some related libraries together in a logical way.  I know that the latest JDevelopper has an option to install those ADF libraries in Maven, but I wanted to do it manually.

Once this was done, it was only a matter of configuring Arquillian to deploy the ADF application on the Embedded Glassfish.  As I previously did a POC with JSF 2 and Arquillian, most of the configuration settings where already there for reuse. The main challenge with Arquillian, JSFUnit and Glassfish is combining the corresponding versions of the dependencies to make it all work together.  Also the ADF version that we are using runs on JSF 1.2, while Glassfish ships with version 2, so I googled how I could fix that.  Just add a sun-web.xml-file to make it work (see solution at http://stackoverflow.com/questions/2333330/jsf-1-2-app-not-working-with-glassfish-v3).

The setup of the Maven project consists of 3 sub projects, namely a Model, a ViewController and an ear project. The Model project is for holding the models of course. In this example I added a simple BC4J component.  For the moment, it still connects to a local installed Oracle database (Express Edition).  In the future, I would like to change it to a local embedded Derby database to make the tests totally isolated.  I also have to add some concrete tests to test the BC4J component completely.

The ViewController project holds my managed bean with the JSP-page, the ADF configuration and the page binding files.  The ear project speaks for itself so the main focus will be on the ViewController project, which is of course the most important one.

As I spent quite a few days on it to make it all work, I decided to share this research as I’m sure this could be useful for other ADF/JSF developers.

You can find the complete project on https://github.com/dabla/adf-maven-demo.

Note that the project holds a setup directory.  This directory contains a bat-file which adds the ADF libraries to your local Maven repository and also copies some parent POM-files for grouping purposes.

Tagged , , , , , , , , , ,
Erik Wramner

Tips and tricks

Java Enterprise Development

Java / Oracle SOA blog

Java Enterprise Development