Monday, 28 November 2011

RequestFactory implementation

This is a record of my implementation of the information contained in the following tutorial:

http://code.google.com/webtoolkit/doc/latest/DevGuideRequestFactory.html

I started with the default implementation of a new AppEngine Connected Android Project and I have been following the tutorial on the Google website:

http://www.youtube.com/watch?v=M7SxNNC429U&feature=player_embedded#!

Sometimes I cut and paste text from the Google website, or change it around slightly, so credit to and acknowledgement to Google where I have done this. It just makes it easier as their terminology is correct.
I wanted to add some gifts (as its Christmas!) to my default AppEngine Connected Android Project. They chose Tasks, I thought Gifts would be more fun :)

First I created my Gift.java class - a simple class with three variables: giftName, giftLocation, giftPrice (all Strings for now) and the getters and setters.

Now the thing that makes this POJO interesting is that I added the annotation @Entity. This describes my class being able to be 'persisted to a data store such as a relational database or the Google App Engine Datastore'.

Gift.java

package com.yrdomain.yrproject.server;

import javax.persistence.*;
import javax.validation.constraints.*;

@Entity
public class Gift {

      private String giftName;
      private String giftLocation;
      private String giftPrice;

      @Id
      @Column(name = "id")
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;

      @Version
      @Column(name = "version")
      private Integer version;

    public String getGiftName() {
        return giftName;
    }
    public void setGiftName(String giftName) {
        this.giftName = giftName;
    }

    public String getGiftLocation() {
        return giftLocation;
    }
    public void setGiftLocation(String giftLocation) {
        this.giftLocation = giftLocation;
    }

    public String getGiftPrice() {
        return giftPrice;
    }
    public void setGiftPrice(String giftPrice) {
        this.giftPrice = giftPrice;
    }

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public Integer getVersion() {
        return version;
    }
    public void setVersion(Integer version) {
        this.version = version;
    }
}
 
I was then able to use File > New > Google > RPC Service to generate me the necessary classes for the RPC service. Its an easy way to create the client-side code that does the basic CRUD operations. The wizard looks for all classes with persistence annotations (and finds Gift.java defined above) and uses this to create the following files in the same package:
  • GiftLocator.java
  • YrprojectService.java
  • YrprojectServiceLocator.java
and the proxy in the shared package:
  • GiftProxy.java
  • YrprojectRequest.java
and a new annotations package:
  • ServiceMethod.java
Lets have a look at some of these...

GiftProxy.java

The GiftProxy is the client-side representation (EntityProxy) of the server-side Gift (Entity). We associate it with the entity in the @ProxyFor annotation and link the persistence implementation with the GiftLocator class.
package com.yrdomain.yrproject.shared;

import com.google.web.bindery.requestfactory.shared.EntityProxy;
import com.google.web.bindery.requestfactory.shared.ProxyForName;

@ProxyForName(value   = "com.yrdomain.yrproject.server.Gift",
              locator = "com.yrdomain.yrproject.server.GiftLocator")
public interface GiftProxy extends EntityProxy {

    String getGiftName();
    void setGiftName(String giftName);

    String getGiftLocation();
    void setGiftLocation(String giftLocation);
    String getGiftPrice();
    void setGiftPrice(String giftPrice);

    Long getId();

    Integer getVersion();
    void setVersion(Integer version);
}
 
GiftLocator.java

The generated file is for when you don't want to implement persistence code in an entity itself. However there are two small problems with the generated file, maybe because the API is so new?
Change Void id to Long id (Eclipse will suggest that you implement all unimplemented methods, which will in effect re-define this method)
@Override
    public Gift find(Class<? extends Gift> clazz, Long id) {
        // TODO Auto-generated method stub
        return null;
    }
Add the missing semi-colon :)
@Override
    public Long getId(Gift domainObject) {
    return domainObject.getId();
    }
 
YrprojectRequest.java

This is found with the GiftProxy.java class in the shared package. This is a RequestFactory service stub, and it must extend RequestContext and uses the @Service or @ServiceName annotations to name the associated service implementation class on the server. The methods in a service stub do not return entities directly, but rather return subclasses of com.google.web.bindery.requestfactory.shared.Request.
This allows the methods on the interface to be invoked asynchronously with Request.fire()from the client.
package com.yrdomain.yrproject.shared;

import java.util.List;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.RequestContext;
import com.google.web.bindery.requestfactory.shared.ServiceName;

@ServiceName(value = "com.yrdomain.yrproject.server.YrprojectService", locator = "com.yrdomain.yrproject.server.YrprojectServiceLocator")
public interface YrprojectRequest extends RequestContext {

    Request<GiftProxy> createGift();
    Request<GiftProxy> readGift(Long id);
    Request<GiftProxy> updateGift(GiftProxy gift);
    Request<Void> deleteGift(GiftProxy gift);
    Request<List<GiftProxy>> queryGifts();
}
 
YrprojectService.java

package com.yrdomain.yrproject.server;

import java.util.List;
import com.yrdomain.yrproject.annotation.ServiceMethod;

public class YrprojectService {

    @ServiceMethod
    public Gift createGift() {
        // TODO Auto-generated method stub
        return null;
    }
    @ServiceMethod
    public Gift readGift(Long id) {
        // TODO Auto-generated method stub
        return null;
    }
    @ServiceMethod
    public Gift updateGift(Gift gift) {
        // TODO Auto-generated method stub
        return null;
    }
    @ServiceMethod
    public void deleteGift(Gift gift) {
        // TODO Auto-generated method stub
    }
    @ServiceMethod
    public List<Gift> queryGifts() {
        // TODO Auto-generated method stub
        return null;
    }
}
 
You'll notice that the Service class above imports a generated annotation class too:


package com.yrdomain.yrproject.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Annotation on method specifying that the method is a service method
 * and needs to have the corresponding request factory code
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface ServiceMethod {
}
 
YrprojectServiceLocator.java

package com.yrdomain.yrproject.server;

import com.google.web.bindery.requestfactory.shared.ServiceLocator;

public class YrprojectServiceLocator implements ServiceLocator {

    @Override
    public Object getInstance(Class<?> clazz) {
        try {
            return clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
 
That's enough for one post... next, making it do stuff!

No comments:

Post a Comment