Thursday, April 18, 2013

Configuring EJB with Restful Web Service in ADF

In current JDeveloper we can expose EJB's as Web Service, however this will be a SOAP based web service. In this article will discuss on configuring EJB with restful web service using jersey support. This article provides an example of building a complete RESTful API using the different HTTP methods:
  • GET to retrieve data
  • POST to add data
  • PUT to update data
  • DELETE to delete data
You can download the sample workspace from here
[Runs with Oracle JDeveloper 11.1.2.3.0 + HR Schema]

Implementation Steps:-

Create a EJB project, then create the DEPARTMENT JPA/EJB 3.0 Entity using the"Entities from tables" EJB wizard, create a Stateless Session bean and select Departments JPA Entity to generates façade methods.

Open the Departments entity and annotate with @XmlRootElement, when a top level class or an enum type is annotated with the @XmlRootElement annotation, then its value is represented as XML element in an XML document. Basically this allow ADF to convert this object directly to XML.JSON.


Add a new project ('REST Web Service Project') in the application and mention the name as WebService. Go to 'Project properties' > 'Dependencies' and add the Model project as a dependency.

Next add the supporting libraries to the Rest Web Service project, go to 'Project properties' > 'Libraries and Classpath'. Libraries are listed in the below screen shot, you can find the libraries in EJBRestService/libs folder.


Create and open EJBRestService java class, annotate with @Path("EJBRESTService") on class level. Click on the @Path notice on the left side yellow bulb will be appeared and click on the bulb to "Configure web.xml for jersey JAX-RS web services" as shown in below.


Now web.xml is created under WEB-INF folder. Open the file and replace with the below xml code.
<?xml version = '1.0' encoding = 'windows-1252'?>
<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">
    <filter>
        <filter-name>JpsFilter</filter-name>
        <filter-class>oracle.security.jps.ee.http.JpsFilter</filter-class>
        <init-param>
            <param-name>enable.anonymous</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>JpsFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
    </filter-mapping>
    <servlet>
        <servlet-name>jersey</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
            <param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>webservice</param-value>
        </init-param>
        <init-param>
            <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--load-on-startup>1</load-on-startup-->
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey</servlet-name>
        <url-pattern>/jersey/*</url-pattern>
    </servlet-mapping>
    <ejb-local-ref>
        <ejb-ref-name>ejb/SessionEJBBean</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <local>model.SessionEJBLocal</local>
        <ejb-link>SessionEJB</ejb-link>
    </ejb-local-ref>
</web-app>
Points to be noticed from the above xml code are :
  1. param-value under com.sun.jersey.config.property.packages tag - change the package name by your own package name used in the application.
  2. Add the Ejb References 
Open the EJBRestService.java file and add the below code.
@Path("EJBRESTService")
public class EJBRestService {
    public EJBRestService() {
        super();
    }

    @GET
    @Produces(MediaType.APPLICATION_XML)
    public List getAllDepts() {
        List list = new ArrayList();
        try {
            Context ic = getInitialContext();
            SessionEJBLocal sessionEJB = (SessionEJBLocal)ic.lookup("java:comp/env/ejb/SessionEJBBean");
            for (Departments departments : (List)sessionEJB.getDepartmentsFindAll()) {
                list.add(departments);
            }
            ic.close();
        } catch (NamingException e) {
            e.printStackTrace();
        }
        return list;
    }

    @POST
    @Consumes(MediaType.APPLICATION_XML)
    public void persistDept(Departments departments) {
        try {
            Context ic = getInitialContext();
            SessionEJBLocal sessionEJB = (SessionEJBLocal)ic.lookup("java:comp/env/ejb/SessionEJBBean");
            sessionEJB.persistDepartments(departments);
            ic.close();
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    @PUT
    @Consumes(MediaType.APPLICATION_XML)
    public void mergeDept(Departments departments) {
        try {
            Context ic = getInitialContext();
            SessionEJBLocal sessionEJB = (SessionEJBLocal)ic.lookup("java:comp/env/ejb/SessionEJBBean");
            sessionEJB.mergeDepartments(departments);
            ic.close();
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    @DELETE
    @Path("{departmentId}")
    public void removeDept(@PathParam("departmentId")
        BigDecimal departmentId) {
        try {
            Context ic = getInitialContext();
            SessionEJBLocal sessionEJB = (SessionEJBLocal)ic.lookup("java:comp/env/ejb/SessionEJBBean");
            Departments departments = new Departments();
            departments.setDepartmentId(departmentId);
            sessionEJB.removeDepartments(departments);
            ic.close();
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    private static Context getInitialContext() throws NamingException {
        InitialContext ic = new InitialContext(); // WebLogic Server 10.x connection details
        return ic;
    }
}
Now deploy/run the EJBRestService.java client in the Integrated Weblogic Server to test. Once client runs it will provide the Target Application WADL/Target URL in JDeveloper console, click on any link to run the service in HTTP Analyzer. Below screen shows the GET method accessed in HTTP Analyzer with result.


Note:- Put and Post method are not working with HTTP Analyzer, you might need to create java client/ADF application to test these methods.

Tuesday, April 2, 2013

Sync Device Back Button With ADF Mobile App's Back Button In TaskFlows

This article is the continuation of my previous article on Handling the Device Back button in ADF Mobile Application. Scenario in this article is to use the device back button to go back to previous page within taskflows, Android device has a back button and our apps should take an advantage of that.

Thanks for Bryan Laipple, in his forum reply he provided the solution on how to programmatically navigate within task flows. Application screen looks like below when it is deployed and run on the Android Device/Emulator. In the below screen Employee list will be displayed.


Clicking on any employee will take you to the selected Employee details page. Notice in the below screen there is no back button provided explicitly, here we can take an advantage of device back button to navigate back to previous page. Now click on the device back button to go back to previous page.


You can download the sample workspace from here. I have checked in Android Device/Emulator and it's working fine.

In below section I will not provide all the steps to create the application from scratch, only key ones are shown. Created DeviceBackButtonTaskFlow.xml taskflow in this application looks like below.


Programmatically navigate within task flows in two ways: -
  • Javascript - Create Javascript file under the feature and add the below code which catches the event that fires when the user presses the device back button. In Javascript function directly call adf.mf.api.amx.doNavigation(outcome), here outcome is the variable that represents the navigation string corresponding to the control flow case.
//This is an event that fires when the user presses the device back button
document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() {
    document.addEventListener("backbutton", backKeyDown, true);
}

function backKeyDown() {
    //Check the device back button action happened in Employee.amx
    if ($('#EmployeeId').length) {
  //Navigate within taskflows using javascript
  adf.mf.api.amx.doNavigation("backToEmployeeList");
    }
}
  • Java - Create Javascript file under the feature and add the below code which catches the event that fires when the user presses the device back button.
//This is an event that fires when the user presses the device back button
document.addEventListener("deviceready", onDeviceReady, false);

function onDeviceReady() {
    document.addEventListener("backbutton", backKeyDown, true);
}

function backKeyDown() {
    //Check the device back button action happened in Employee.amx
    if ($('#EmployeeId').length) {
        //Call the java method in managed bean
        adf.mf.api.invokeMethod("mobile.EmployeeManagedBean", "handleNavigation", onInvokeSuccess, onFail);
    }
}

function onInvokeSuccess(param) {
    //To do code after success
};

function onFail() {
    //To do code after failure
};
Next create a EmployeeManagedBean class under DeviceBackButtonTaskFlow. Add the below code to navigate within the taskflow. This method will be called from javascript function.
public void handleNavigation() {
        //Code to naviagte within task flows programmatically
        AdfmfContainerUtilities.invokeContainerJavaScriptFunction(AdfmfJavaUtilities.getFeatureName(),
                                                                  "adf.mf.api.amx.doNavigation",
                                                                  new Object[] { "backToEmployeeList" });
}

Oracle JDeveloper and Oracle ADF 11g Release 1 (11.1.1.7.0) released

The 11g Release 1 (11.1.1.7.0) version of JDeveloper and ADF is a minor update release, download here. It contains many bug fixes as well as a few new features to enjoy.