Monday, November 15, 2010

GWT 2.1: Request Factory

RequestFactory is the new machanism to ease client/server data transfer. It brings you the possibility to define data centric code on server side, and to define business component on client side.

Entity

It is the base class of the mechanism. It is the DAO implementation class and it should be located to a shared package (accessible from both, client side and server side). It is not mandatory that this entity be a JPA entity, but RequestFactory constraints made entities looks like JPA entities.

public class Employee {
private String userName;
private String department;
private String password;
private Long id;
private Employee supervisor;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Employee getSupervisor() {
return supervisor;
}
public void setSupervisor(Employee supervisor) {
this.supervisor = supervisor;
}

public static Long countEmployees() {
return 2l;
}

public void persist() { }

public static Employee findEntity(Long id) {
return new Employee();
}

public Integer getVersion() {
return 0;
}
}
Above, we can see a POJO that defines en Employee. It implements getter end setters for each attribute, and methods countEmployees, findEntity and getVersion. Methods findEntity and getVersion are mandatory and are used internally by RequestFactory. Method countEmployees

is a data access method that could be used on client.

Entity Proxy

Entity proxy is the entity client side representation, well known as Data Transfer Object. It must implements EntityProxy and provides methods to access (read/write) to data stored in the entity. You haven't to provides data access methods such as countEmployees().

@ProxyFor(Employee.class)
public interface EmployeeProxy extends EntityProxy {

String getUserName();
void setUserName(String userName);
String getDepartment();
void setDepartment(String department);
String getPassword();
void setPassword(String password);
Long getId();
void setId(Long id);
Employee getSupervisor();
void setSupervisor(Employee supervisor);
}
Annotation @ProxyFor specifies the entity class to proxy. EntityProxy are objects used on client side, as Entities are objects user on server.

Request

Request defines an interface to use data access method. It is interface that deals with the server, and it can be seen as the service interface.
@Service(Employee.class)
public interface EmployeeRequest extends RequestContext {

Request<Long> countEmployees();

InstanceRequest<EmployeeProxy, Void> persist();
}

This interface defines methods that can be served and must be the same signature (except for return type) than the concrete service (on server). The return type must be a Request object parameterized with the return type of the server service. Request class is used for static methods, for instance method, such persist, it is InstanceRequest that is used to specify the instance type, and the method return code.

Annotation @Service gives the service class object. In our case, it is the same than the entity, but it can be different. It is only a current practice in JPA to merge DAO and entity.

Request Factory

RequestFactory allows to define a central point to create each RequestContext implementation. It is the interface that is directly instanciated (via deferred binding) by the developer.

public interface EmployeeRequestFactory extends RequestFactory {

EmployeeRequest employeeRequest();
}

Putting it all together

To use al of this stuff, first, we have to declare RequestFactory servlet:
<servlet>
<servlet-name>gwtRequest</servlet-name>
<servlet-class>com.google.gwt.requestfactory.server.RequestFactoryServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>gwtRequest
<url-pattern>/gwtRequest
</servlet-mapping>

And we have to create the RequestFactory and to give it a EventBus:
EmployeeRequestFactory factory = GWT.create(EmployeeRequestFactory.class);
factory.initialize(new SimpleEventBus());

Now, we can use it. To call a server side static method, we have to get the RequestContext and call the method on it. To execute it effectively, Request defines a method fire that executes the method to the server, and takes a Receiver in parameter. Receiver provides callback methods to execute some code. Defined callback are:

  • onFailure: in case of an error occured on server
  • onSuccess: to get the result
  • onViolation: when validation failed. Validation is supported by the RequestFactory. Validation rules should be set on entity.
factory.employeeRequest().countEmployees().fire(new Receiver<Long>() {
@Override
public void onSuccess(Long response) {
// implementation
}
});

Creating a proxy should not be done by using deferred binding (GWT.create):

EmployeeProxy employee = factory.employeeRequest().create(EmployeeProxy.class);

One time a proxy is created, we can persist it on server:

factory.employeeRequest().persist().using(employee).fire();

A call to fire() is equivalent to:

fire(new Receiver() {
@Override
public void onSuccess(Object response) {
// implementation
}
});

RequestFactory supports relationship, it sends a whole object rgaph for persistence, but it does not support embedded object.

4 comments:

  1. If I want to implement a DAO class, pointed in the @Service annotation, it would be a good idea to implement static methods for persist, remove? Passing the entityProxies as parameters of the method? As here, and in the google trunks are implemented as instance method for passing the entityProxies in the using method parameter.

    ReplyDelete
  2. Could you upload your sample code?

    ReplyDelete
  3. could u upload the full zip code??

    ReplyDelete
  4. Hi. Could you upload the full source code?

    ReplyDelete