You are on page 1of 34

Direct Web Remoting,

Hibernate and Dojo.E

“Easy Ajax for Java”


Joel Barciauskas
October 3, 2008
What is DWR?
• “Easy Ajax for Java” implies two parts
– Server – Java servlet
– Client – JavaScript auto-generated by the Java
servlet
• Enables JSON to JavaBean serialization
• Exposes selected methods and JavaBean
properties on the server as client-side
JavaScript methods and objects
• Reverse Ajax – IMB-like functionality
Why use DWR? Why not?
• Pros
– Avoid replication of effort defining model objects on both
server and client
– No XHR boilerplate required
– No serialization boilerplate
– JSON is fastest format to serialize/deserialize in the browser
• Cons
– Less control over network requests
 E.g., harder to bundle requests
– Not RESTful, all requests processed through POST data
rather than URLs
 Best for single-page applications
Let’s see it
• Application: Simple database create and
read
• Using: JavaScript, DWR 2.0, Hibernate
3.0, Derby
• Shell:
http://source.nexaweb.com/svn/repos/trunk/tu
Create your domain class
(JavaBean)
• src/events/Event.java
package events;
import java.util.Date;
public class Event {
private Long id;
private String title;
private Date date;
public Event() {}
public Long getId() { return id; }
private void setId(Long id) { this.id = id; }
public Date getDate() { return date; }
public void setDate(Date date) { this.date = date; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
}
Create Hibernate XML Mapping
• src/events/Event.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-
//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-
mapping-3.0.dtd">
<hibernate-mapping>
<class name="events.Event" table="EVENTS">
</class>
</hibernate-mapping>
Add Property Mappings
• src/events/Event.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping
DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-
3.0.dtd">
<hibernate-mapping>
<class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID">
<generator class="native"/>
</id>
<property name="date" type="timestamp"
column="EVENT_DATE"/>
<property name="title"/>
</class>
</hibernate-mapping>
Create Hibernate Configuration
• src/hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- Database connection settings -->
<property name="connection.driver_class">org.apache.derby.jdbc.EmbeddedDriver</property>
<property name="connection.url“>jdbc:derby:eventDB;create=true</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.DerbyDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
<mapping resource="events/Event.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Create SessionFactory instance
• src/util/HibernateUtil.java
package util;
import org.hibernate.*;
import org.hibernate.cfg.*;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try { // Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() { return sessionFactory; }
}

Note: This can also be achieved through the Spring integration – “use the Spring
OpenSessionInViewFilter which will ensure that a Hibernate Session is open” (http://
directwebremoting.org/dwr/server/hibernate)
Create an Event Manager
• src/events/EventManager.java
package events;
import org.hibernate.Session;
import java.util.Date;
import java.util.List;
import util.HibernateUtil;
public class EventManager {
public void createAndStoreEvent(String title, Date theDate) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);
session.save(theEvent);
session.getTransaction().commit();
}

public List listEvents() {


Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List result = session.createQuery("from Event").list();
session.getTransaction().commit();
return result;
}
}
Add the DWR servlet to web.xml
• WebContent/WEB-INF/web.xml
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<display-name>DWR Servlet</display-name>
<servlet-class>
org.directwebremoting.servlet.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>
Create a Remote Proxy and Expose Remote Methods

• Src/events/EventManager.java
package events;
import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.annotations.RemoteProxy;
import org.hibernate.Session;
import java.util.Date;
import java.util.List;
import util.HibernateUtil;

@RemoteProxy
public class EventManager {
@RemoteMethod
public void createAndStoreEvent(String title, String theDate) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDateString(theDate);
session.save(theEvent);
session.getTransaction().commit();
}

@RemoteMethod
public List listEvents() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List result = session.createQuery("from Event").list();
session.getTransaction().commit();
return result;
}
}
Annotate Event as a Data Transfer
Object
• src/events/Event.java
package events;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.directwebremoting.annotations.DataTransferObject;
import org.directwebremoting.annotations.RemoteProperty;

@DataTransferObject
public class Event {

@RemoteProperty
private Long id;
@RemoteProperty
private String title;
private Date date;
public Event() {}
public Long getId() {
return id;
}
private void setId(Long id) {
this.id = id;
}
@RemoteProperty
public String getDateString() {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
return sdf.format(this.date);
}

[continued on next slide]


Annotate Event as a Data Transfer Object
(con’t)
• src/events/Event.java [continued]

@RemoteProperty
public void setDateString(String dateStr) {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
try {
this.date = sdf.parse(dateStr);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}

Note: We added getDateString and setDateString here, because there is no implicit conversion available between
JavaScript dates and Java dates – mostly arrays, strings, BigNumber, and primitives. See
http://directwebremoting.org/dwr/server/dwrxml/converters for more information.
Update web.xml
• WebContent/WEB-INF/web.xml
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>classes</param-name>
<param-value>
events.Event,
events.EventManager
</param-value>
</init-param>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
Using DWR Debug Mode
• Go to
http://localhost:8080/DWRExample/dwr/
– Click “EventManager”
– Enter “Event 1” in the first parameter of
createAndStoreEvent
– Enter “10/01/2008” in the second parameter

• Click the Execute button


• Click the Execute button next to
listEvents()
Let’s add DWR on the client side
• File->New->Web->HTML->
WebContent/index.html
• Open and edit title “DWR Example”
• Go back to
http://localhost:8080/DWRExample/dwr/test/E
and copy and paste the script tags
More Dojo boilerplate
• Paste the following too:
<script type="text/javascript" src="js/dojo/dojo/dojo.js"
djConfig="isDebug: true, parseOnLoad: true"></script>
<link rel="stylesheet" type="text/css"
href="js/dojo/dojo/resources/dojo.css" />
<link rel="stylesheet" type="text/css"
href="js/dojo/dijit/themes/tundra/tundra.css" />
<link rel="stylesheet" type="text/css"
href="js/dojo/dojox/grid/_grid/Grid.css" />
<link rel="stylesheet" type="text/css"
href="js/dojo/dojox/grid/_grid/tundraGrid.css" />

<script type="text/javascript">
dojo.require("dijit.form.Button");
dojo.require("dijit.form.TextBox");
dojo.require("dijit.form.DateTextBox");
dojo.require("dojox.grid.Grid");
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dojoe.dojoe");
</script>
Add Dojo.E
• Add tundra class to body tag:
<body class="tundra">
• Create XML file
WebContent/dwrDojoE.xml
• And add tag
<script type="text/xml"
dojoType="dojoe.XmlScript"
src="dwrDojoE.xml"></script>
Edit Dojo.E
• WebContent/dwrDojoE.xml
<ui xmlns="html" xmlns:dijit="dijit"
xmlns:dojox="dojox">
<dijit:form.Button>
Refresh
</dijit:form.Button>
<dojox:grid.Grid id="gridNode" jsId="grid"
elasticView="0" style="height:300px;
width:500px"/>
</ui>
Where’s the Grid?!?
Create a grid layout
• WebContent/index.html
<body class="tundra">'
<script type="text/javascript">
var layout = [{
cells: [[
{
name: 'Event ID',
field: 'id',
width: 'auto'
},
{
name: 'Date',
field: 'dateString',
width: 'auto'
}, {
name: 'Event',
field: 'title',
width: 'auto'
}]]
}];
</script>

Note the correlation between the field values above and the RemoteProperty defintions of Event.java
Add the layout to the Grid
• WebContent/dwrDojoE.xml
<ui >
<dijit:form.Button>
Refresh
</dijit:form.Button>
<dojox:grid.Grid id="gridNode"
structure=“layout”
jsId="grid" elasticView="0"
style="height:300px; width:500px"/>
</ui>
Now let’s get some data
• WebContent/index.html
var putEvents = function(list){
var dataStore = new Array;
dataStore["items"] = list;
dataStore["label"] = "title";

var model = new dojox.grid.data.DojoData(null, null, {


jsId: 'model',
store: new dojo.data.ItemFileReadStore({
data: dataStore
}),
query: {
title: '*'
}
});

grid.setModel(model);
grid.refresh();
grid.render();
};
Update Dojo.E
• WebContent/dwrDojoE.xml
<ui>
<dijit:form.Button
onClick="EventManager.listEvents(putEvents)">
Refresh
</dijit:form.Button>
<dojox:grid.Grid id="gridNode" jsId="grid"
elasticView="0" style="height:300px;
width:500px"/>
</ui>
Click Refresh
Create a method to create an
event
• WebContent/index.html
var createEvent = function(titleId, dateId){
var title = dojo.byId(titleId).value;
var date = dojo.byId(dateId).value;
EventManager.createAndStoreEvent(title,
date);
EventManager.listEvents(putEvents);
};
Let’s Add Input Controls
• WebContent/dwrDojoE.xml
<ui >
<dijit:form.Button onClick="EventManager.listEvents(putEvents)">
Refresh
</dijit:form.Button>
<dojox:grid.Grid id="gridNode" jsId="grid" structure="layout" elasticView="0“
style="height:300px; width:500px"/>
<label for="eventTitle" style="float: left;">Event Title:</label>
<dijit:form.TextBox style="float: left;" id="eventTitle" value=""/>
<label for="eventDate" style="float: left;">Event Date:</label>
<dijit:form.DateTextBox id="eventDate" value="" style="float: left;"/>
<dijit:form.Button style="float: left;“
onclick="createEvent('eventTitle', 'eventDate')" label="Add Event">
</dijit:form.Button>
</ui>
Reload the page
Enter a title and date
Load data at startup
• WebContent/index.html
dojo.addOnLoad(function() {
EventManager.listEvents(putEvents);
});
Final note
• If using more complex object models with
Hibernate, use the
HibernateBeanConverter3 – See http://
directwebremoting.org/dwr/server/hibernate