Thursday, November 29, 2007

AJAX Simplified: JDeveloper and Enterprise JavaBeans (EJB)

When developing rich internet applications (RIA) for our hosted applications and applications I have developed for clients I have generally used Spring, JDBC, DWR, JavaScript and DOJO. For my next development project I am toying with replacing JDBC with EJB. JDeveloper is very intuitive in creating EJB models and the wizards within the tool speed up development. In this post I'm simply going to be talking about hooking up DWR with EJBs.

If you are not familiar with creating EJBs in JDeveloper start with this tutorial. I will only be covering setting up your web project to expose your EJB methods. The web project that is built in this post is based off of the EJB project created in the tutorial.

Prerequisites

JDeveloper 10.1.3

DWR 1.4

Oracle DB

Create web project and configure properties

Create a new WebProject within the same workspace as your EJB model project. As you go through the "Web Project Wizard" select to create a new JSP page. After you have completed the wizard double-click on your project and select Dependencies. Make sure your EJB project is selected. With the project properties still open select Libaries. Add new libraries so that they look similar to the following:

Notice the Dwr.jar entry. Download the jar from here and save into /WEB-INF/lib directory. You might have to create that directory.

HINT: You can expedite the above without having to manually configure your web project. I started by creating a web project first. I then went into my EJB Model project, right-clicked on my Session bean and selected "New Simple Java Client". I used the wizard to create the Java client in my already created web project. This automattically configured my project with the exception of adding dwr.jar.

Create a Service Class

The service class will be used to expose our Java methods to DWR. DWR will inspect this class and expose our methods using JavaScript. I will not be covering JavaScript in this post.

Create a new Java class in your WebProject. Following is the code I have in this class:

package dwr.service;

import dwr.buslogic.Employees;
import dwr.buslogic.SessionEJBFacade;

import dwr.client.SessionEJBFacadeClient;

import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class HRService {
static Log log = LogFactory.getLog(HRService.class);
private Context context;

/**
* When this class is instatiated we'll want to get our context for
* looking up our beans
*/
public HRService() {
log.debug("Service instatiating....");
try {
context = getInitialContext();
} catch (NamingException ne) {
log.fatal(ne);
}
}

/**
* Return all employees
*/
public List<Employees> getEmployees() throws NamingException {

log.debug("getEmployees");

// lookup our session bean
SessionEJBFacade sessionEJBFacade =
(SessionEJBFacade)context.lookup("SessionEJBFacade");

return sessionEJBFacade.queryEmployeesFindAll();
}

/**
* Return a single employee based on their employee id
*/
public List<Employees> getEmployee(long empid) throws NamingException {
log.debug("getEmployee(empid=" + empid + ")");
SessionEJBFacade sessionEJBFacade =
(SessionEJBFacade)context.lookup("SessionEJBFacade");
return sessionEJBFacade.queryEmployeesFindById(empid);
}

/**
* Create our context
*/
private static Context getInitialContext() throws NamingException {
// Get InitialContext for Embedded OC4J
// The embedded server must be running for lookups to succeed.
return new InitialContext();
}
}

Configuring DWR

In order for DWR to work we must create a dwr.xml file. This file needs to be in the same location as web.xml. Within your WebProject expand /WEB-INF folder and create a new xml file named dwr.xml. Following is what I have in my dwr.xml to expose the Java class created above:

<!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr//dwr20.dtd">
<dwr>
<allow>
<create creator="new" javascript="HRService">
<param name="class" value="dwr.service.HRService"/>
</create>
<convert converter="bean" match="dwr.buslogic.Employees">
<param name="include" value="firstName,lastName"/>
</convert>
</allow>
</dwr>

The <create> element is telling DWR what class we want to have exposed via JavaScript. By default we are going to have DWR inspect our class and expose all available public methods. We could specify specific methods if we would like to.

The <convert> element ensures all of our parameters are converted properly by DWR. The class "dwr.buslogic.Employees" is the class that was created for me in my EJB Model project. I am also specifying that I only want firstName and lastName attributes exposed.

Configure web.xml

Your web.xml file must be configured to run the DWR servlet. See the following for an example:

<?xml version = '1.0' encoding = 'windows-1252'?>
<web-app xmlns:xsi="
http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee">
<description>Empty web.xml file for Web Application</description>
<session-config>
<session-timeout>35</session-timeout>
</session-config>
<mime-mapping>
<extension>html</extension>
<mime-type>text/html</mime-type>
</mime-mapping>
<mime-mapping>
<extension>txt</extension>
<mime-type>text/plain</mime-type>
</mime-mapping>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>uk.ltd.getahead.dwr.DWRServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
</web-app>

Project Make-up

For a simple reference following is a screen shot of the Application Navigator in JDeveloper:

Ready to Run

If you want to put some text on your JSP page you created you can but there is no reason. Simply right click on your JSP page and select run. Once the application starts, your JSP page will appear. In the address bar change your location so that you go to /dwr/ (back out the name of your jsp page) and you'll see something similar to the following:

Test DWR

The DWR page will display the class(es) that are known to DWR. Click on the link and you'll see a list of all of the methods that have been exposed. This page makes it very easy to test your DWR methods without having to write any code. Eventually when you are ready to move your application to production you'll want to turn this page "off". You can do this by updating your web.xml.

Click on the methods from your class to make sure they work:

JavaScript Primer

If you view the source from the DWR test page you'll see the very small amount of JavaScript required to display the data. Here is the code from the getEmployees() button on my page:

<input class='ibutton' type='button' onclick='HRService.getEmployees(reply0);' value='Execute' title='Calls HRService.getEmployees(). View source for details.'/>
<script type='text/javascript'>
var reply0 = function(data)
{
if (data != null && typeof data == 'object') alert(dwr.util.toDescriptiveString(data, 2));
else dwr.util.setValue('d0', dwr.util.toDescriptiveString(data, 1));
}
</script>

Next Steps

For now I didn't get into details regarding how I code JavaScript to interface with DWR. I will cover that in a subsequent post. But for now you should be able to see how easy it was for me to create EJBs in JDeveloper and expose them to my browser.

Email me if you would like me to send you this project from JDeveloper.

No comments: