gwtXPDownloadsBlog

Invoke GWT RPC services deployed on Google App Engine

Posted in AppEngine, GWT on March 13th, 2010 3 Comments

SyncProxy allows you to invoke GWT RPC services from pure Java (no JSNI) code.
From version 0.1.2, you can invoke your RPC services deployed on AppEngine.

This post shows you how to use this new feature of SyncProxy.

The service interface

For example, we have an helloApp application and a RPC service GreetingService

@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
  String greetServer(String name);
}

And the service implementation is as below

public class GreetingServiceImpl extends RemoteServiceServlet
      implements GreetingService {
  public String greetServer(String name) {
    return "Hello, " + name;
  }
}

Assume the application is deployed on AppEngine and the servlet URL is configured at http://example.appspot.com/helloApp/greet

Java client code

Create new proxy instance for the service interface:

private static GreetingService rpcService =
  SyncProxy.newProxyInstance(GreetingService.class,
        "http://example.appspot.com/helloApp", "greet");

This will create a new proxy instance which implements your GreetingService.

Then invoke the service method.

String result = rpcService.greetServer("SyncProxy");

Secure your service

We modify our service implement which enforce user to login to access to the service:

public class GreetingServiceImpl extends RemoteServiceServlet
      implements GreetingService {
  public String greetServer(String name) {
    // implement the security
    UserService userService = UserServiceFactory.getUserService();
    if (!userService.isUserLoggedIn()){
      throw new RuntimeException("Access Denied");
    }
    // We can also enforce only admin user can access to the service
    /*
    if (!userService.isUserAdmin()){
      throw new RuntimeException("Access Denied");
    }
    */

    return "Hello, " + name;
  }
}

Invoke the secured service

Before invoke the secured service, you have to login to the application.

SyncProxy.loginGAE("https://example.appspot.com",
    "http://example.appspot.com/helloApp/greet",
    "yourusername@gmail.com", "yourpassword");

Then invoke the service method.

String result = rpcService.greetServer("SyncProxy");

Download SyncProxy

Get SyncProxy (with source code) at our Downloads page

Share and Enjoy:

  • Google Bookmarks
  • Twitter
  • Facebook
  • Digg
  • Technorati
  • Live
  • DZone
  • Reddit
  • del.icio.us
  • Mixx
  • Netvibes
  • StumbleUpon
  • Yahoo! Bookmarks
  • Yahoo! Buzz
  • email
Leave a Comment »

Data Binding in GWT and gwtXP

Posted in GWT, gwtXP on March 6th, 2010 Be the first to comment

Table of Contents

 

Introduction

gwtXP uses JFace data binding (with modifications) and Expression Language concepts to allow you declare binding expression like <g:textBox text="${user.userId}"/>.

This post shows how to use data binding (property binding, list binding and table binding) in gwtXP to build gwt applications. It also shows how to build a scrollable table. See the demo.

Data model

We use following bound bean during this post. See the examples page for complete source code.

public class User{
  private transient PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);

  private String userId;
  private String fullName;
  private Date dob;
  private String email;
  private int numberOfWrongPassword;
  private String password;
  private Boolean enabled;
  ...
  // getter and setter methods
}

Basic binding

Bind a bean’s property to a GWT widget’s property. gwtXP supports most of common widgets such as Label, TextBox, PasswordTextBox, CheckBox, RadioButton, Button, etc.

Below shows some basic binding examples:

Bind to Label text

<g:label text="${user.userId}"/>

Bind to TextBox text

<g:textBox text="${user.userId}"/>

If you require the build-in user ‘admin’ can not be changed, you can disable the text box for userId value of ‘admin’:

<g:textBox text="${user.userId}" enabled="${user.userId != 'admin'}"/>

Bind to PasswordTextBox’s text and enabled properties

For example, you require the admin can set new password for enabled user only, e.g the password text box will be enabled if user.enabled is true.

<g:passwordTextBox text="${user.password}" enabled="${user.enabled}"/>

Bind to CheckBox value

<g:checkBox value="${user.enabled}"/>

Data Conversion

The data binding has build-in data converter which converts one object to another object, for example from Date to String, Number to String, etc and vice versa. Some converter requires additional ‘pattern’ attribute. The ‘pattern’ attribute describe how a converter format/parse data. If no ‘pattern’ specified, the converter uses the default one.

In gwtXP, simply add ‘pattern’ attribute to the tag as below:

<g:textBox text="${user.dob}" pattern="MM/dd/yyyy"/>

The converter also validate user input against the specified pattern.

Custom Data Validation

You can declare the validator which validate the user input as below:

<g:textBox text="${user.email}" validator="${emailValidator}"/>

The validator must implement the IValidator interface.

Validation Status

When the validating the data, validator will report a status (whether OK or error). By default, when error occurs during validation process, we add an ‘error’ style to the widget. To display the error message, we use a special errors tag as below:

<g:errors errorMessage="There was errors during validating your data."/>

Of course, you can internationalize the error message as below:

<g:errors errorMessage="${constants.multipleErrors}"/>

Read full article »

Share and Enjoy:

  • Google Bookmarks
  • Twitter
  • Facebook
  • Digg
  • Technorati
  • Live
  • DZone
  • Reddit
  • del.icio.us
  • Mixx
  • Netvibes
  • StumbleUpon
  • Yahoo! Bookmarks
  • Yahoo! Buzz
  • email
Leave a Comment »

GWT SyncProxy 0.1.1

Posted in GWT on February 25th, 2010 Be the first to comment

GWT SyncProxy allows you to access/invoke GWT RPC service methods from pure Java (non JSNI) code.

See the previous post http://www.gdevelop.com/w/blog/2010/01/10/testing-gwt-rpc-services/ for how to use GWT SyncProxy to test GWT RPC services without using GWTTestcase.

SyncProxy 0.1.1 is released with following changes:

  • Support cookie. At the moment, the cookie is stored in memory only.

Get SyncProxy (source code included) at the Downloads page.

Share and Enjoy:

  • Google Bookmarks
  • Twitter
  • Facebook
  • Digg
  • Technorati
  • Live
  • DZone
  • Reddit
  • del.icio.us
  • Mixx
  • Netvibes
  • StumbleUpon
  • Yahoo! Bookmarks
  • Yahoo! Buzz
  • email
Leave a Comment »

Testing GWT RPC services

Posted in GWT on January 10th, 2010 59 Comments

You may know that testing with GWTTestCase are very slow. And there are many posts about testing GWT applications without using GWTTestCase.

However, it is still hard to test our RPC remote services. That is the reason I decided to develop SyncProxy which can run directly from pure Java (non JSNI) code.

Simple Test case

For example, we have an helloApp application and we want to test our GreetingService

@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
  String greetServer(String name);
}

Assume the server side of application is running (whether in DevMode or deployed to an web server) and the servlet URL is configured at http://localhost/helloApp/greet

The test case

public class GreetingServiceTest extends TestCase{
  private static GreetingService rpcService =
    SyncProxy.newProxyInstance(GreetingService.class,
          "http://localhost/helloApp", "greet");

  public void testGreeting() {
    String result = rpcService.greetServer("SyncProxy");
    assertTrue((result != null) && (result.startsWith("Hello, SyncProxy")))
  }
}

Explanation

SyncProxy.newProxyInstance() method requires a service interface class, a base URL and a relative servlet path.

SyncProxy will search for RPC policy files (*.gwt.rpc files) to determine appropriate policy name for the service interface. Thus, we copy gwt.rpc files from war/helloApp directory to our test case classpath.

SyncProxy.newProxyInstance() will return a new proxy instance which implements our GreetingService interface.

Simulating Async

By design SyncProxy is synchronous, e.g it invoke the remote service and wait for the result. However, our GWT logic code invokes the remote service asynchronously. SyncProxy can simulate the ‘Async’ mode too.

GreetingServiceAsync rpcServiceAsync =
SyncProxy.newProxyInstance(GreetingServiceAsync.class,
          "http://localhost/helloApp", "greet");

The code is almost the same as section above, except we use the Async version of the remote service interface.

rpcService.greetServer("SyncProxy", new AsyncCallback<String>(){
  public void onFailure(Throwable caught) {
    ...
  }
  public void onSuccess(String result) {
    ...
  }
});

Download SyncProxy

Get SyncProxy (with source code) at our Downloads page

SyncProxy includes test suite (see the Java source file com.gdevelop.gwt.syncrpc.test.RPCSyncSuite) to test against the standard GTW RPC test.

Updated on 2010/03/03: Version 0.1.1 is released with cookie supports

Updated on 2010/03/13: New post Invoke GWT RPC services deployed on Google App Engine.

Share and Enjoy:

  • Google Bookmarks
  • Twitter
  • Facebook
  • Digg
  • Technorati
  • Live
  • DZone
  • Reddit
  • del.icio.us
  • Mixx
  • Netvibes
  • StumbleUpon
  • Yahoo! Bookmarks
  • Yahoo! Buzz
  • email
Leave a Comment »

GWT Map Generator

Posted in GWT on January 5th, 2010 Be the first to comment

When working with GWT History, we usually need a Map for view transitions.

Traditional approach

For example, our EntryPoint class

public class MyEntryPoint implements EntryPoint, ValueChangeHandler{
  ...

  public void onModuleLoad() {
    History.addValueChangeHandler(this);
  }

  public void onValueChange(ValueChangeEvent event) {
    String token = event.getValue();

    if (token != null) {
      Panel panel = null;

      if (token.equals("list")) {
        panel = new ContactsListPanel();
      } else if (token.equals("add")) {
        panel = new EditContactPanel();
      }else if (token.equals("edit")) {
        panel = new EditContactpanel();
      }

      if (panel != null) {
        container.setWidget(panel);
      }
    }
  }
}

Generator

We can archive this by a simple generator

public class MapGenerator extends Generator{
  public String generate(TreeLogger logger, GeneratorContext context,
                         String requestedClass) throws UnableToCompleteException{
    TypeOracle typeOracle = context.getTypeOracle();
    assert(typeOracle != null);

    JClassType baseType = typeOracle.findType(requestedClass);
    if (baseType == null){
      logger.log(TreeLogger.ERROR, "Unable find type " + requestedClass, null);
      throw new UnableToCompleteException();
    }
    String packageName = baseType.getPackage().getName();
    String baseName = baseType.getSimpleSourceName();
    String simpleName = baseName + "Map";
    JClassType[] types = baseType.getSubtypes();

    // Generate the source file
    PrintWriter printWriter = context.tryCreate(logger, packageName, simpleName);
    ClassSourceFileComposerFactory composer =
      new ClassSourceFileComposerFactory(packageName, simpleName);
    composer.setSuperclass("HashMap");
    composer.addImport("java.util.*");
    SourceWriter out = composer.createSourceWriter(context, printWriter);
    out.println("public " + simpleName + "(){");
    out.indent();
    for (JClassType type : types) {
      String key = type.getSimpleSourceName();
      if (key.endsWith(baseName)){
        key = key.substring(0, key.length() - baseName.length());
      }
      out.println("put(\"" + key + "\", new " + type.getQualifiedSourceName() + "());");
    }
    out.outdent();;
    out.println("}");
    out.commit(logger);

    return packageName + "." + simpleName;
  }
}

The Generator will look for all sub-class of requestedClass, and put an instance of each these classes to a HashMap.

Setting up your module

<module>
  ...
  <generate-with class="com.example.rebind.MapGenerator">
    <when-type-assignable class="com.example.client.MyBasePanel" />
  </generate-with>
</module>

Using the generated Map

public class MyEntryPoint implements EntryPoint, ValueChangeHandler{
  private static final Map<String, MyBasePanel> TOKEN_MAP = GWT.create(MyBasePanel.class);
  ...

  public void onModuleLoad() {
    History.addValueChangeHandler(this);
  }

  public void onValueChange(ValueChangeEvent event) {
    String token = event.getValue();

    if (token != null) {
      Panel panel = TOKEN_MAP.get(token);

      if (panel != null) {
        container.setWidget(panel);
      }
    }
  }
}
Share and Enjoy:

  • Google Bookmarks
  • Twitter
  • Facebook
  • Digg
  • Technorati
  • Live
  • DZone
  • Reddit
  • del.icio.us
  • Mixx
  • Netvibes
  • StumbleUpon
  • Yahoo! Bookmarks
  • Yahoo! Buzz
  • email
Leave a Comment »


Recent Comments:

  • Colin: @Piotr Szaranski: I had the same issue with authentication, and I also was looking for...
  • Ora Finona: This is a bit off discussion, which I apologize for, but would you and your readers...
  • Amos: First, thanks for some great software. This is great to have. Here are collection of notes...
  • Peter Frankmann: Hallo zusammen, Sehr gute Beiträge. Danke dafür. Werde wohl noch öfters mal...
  • Trung: SyncProxy depends in gdata java client, thus download it from code.google.com Hope this...