miércoles, 31 de octubre de 2012

Using YUI in GWT UIBinder

About this document 

This document try to document a new feature of the toolkit YUIGWT for using YUI markup in GWT UIBinder.  It will no try to teach you how to use neither YUI or YUIGWT or GWT UIBinder (the user is supposed to know the basics of these technologies).

Online tests


YUIGWT example gallery contains the first tests related to using YUIGWT and UIBinder. The examples are:
  • uibinder test 1 - contains some yui widgets and GWT widgets mixed - layouting using YUI cssgrids.
  • just one, making more for the 1001 usescase... stay in touch....

Introduction

In GWT applications it is common to use UIBinder to separate the markup and style (design) from Java code (behavior).

And YUI proposes a very similar thing. All YUI widgets can be created from a markup structure. This markup structure is defined by each YUI widget. Some simple widgets like Y.Button only requires you to give a <button> element, but other more complicated YUI widgets like tabview, treeview, etc need you to provide a more complex markup (example).  This is somehow related to yui philosophy's of "Progressive Enhancement" @see http://yuilibrary.com/yui/docs/tutorials/gbs/

UIBinder users can mix both GWT Widgets markup and plain HTML Markup in their UI. Also the user is able to bind some of these markup elements to actual Java Objects fields in its Java code where the behavior, controller and modeling of the application is written.

In this document we will discuss how to use YUI Widgets proposed markup together with GWT UIBinder for rendering YUI components using UIBinder in a YUIGWT application.

Solution Summary

In general, the solution proposed here is the user to write YUI plain HTML markup for its YUI widgets in the UIBinder ui.xml, and mark them with an special class name for indicating the framework that that HTML element is a YUI widget and must be "post rendered". Then the user binds these widget elements in the UIBinder java's and after creating the UIBinder main Widget, ask the framework to render all the YUI elements. Later in the code, the user can ask the framework to return the appropiate YUIGWT Widget java class from a certain html element for work with the widget in Java. Hope this can be cleared in the following:

Example

In the following UIBinder example we use YUI cssgrids for layouting, create a yui tabview with some mixed YUI and GWT buttons inside:We commented each YUI element introduced in the markup:

<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
 xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:y="urn:import:org.sgx.yuigwt.ui">

<ui:style>
</ui:style>


<g:HTMLPanel>

 <!-- yui cssgrids -->
 <div class="yui3-g">
  <div class="yui3-u-5-24">
   <!-- yui button -->
   <button ui:field="yuiButton1" class="yui-button">the first YUI Button</button>

   <p>lak sjdlkaj slkdj alk sdlkaj slkdj lak sk djla sd</p>
   <p>lak sjdlkaj slkdj alk sdlkaj slkdj lak sk djla sd</p>

  </div>
  <div class="yui3-u-19-24">

   <!-- YUI tabview -->
   <div ui:field="tabView1" class="yui-tabview">
    <ul>
     <li>
      <a href="#foo">foo</a>
     </li>
     <li>
      <a href="#bar">bar</a>
     </li>
     <li>
      <a href="#baz">baz</a>
     </li>
    </ul>
    <div>
     <div id="foo">

      Some content with two buttons - one yui's and other GWT's<br />
      
      <!-- a YUI button -->
      <button ui:field="yuiButton2" class="yui-button">another yui button</button>
      
      <!-- a gwt button -->
      <g:Button ui:field="gwtButton2">..aGWTButton..</g:Button>

     </div>
     <div id="bar">
      a single GWT button:
      
      <g:Button text="GWT button1" ui:field="gwtButton1"></g:Button>
     </div>
     <div id="baz">baz content</div>
    </div>
   </div>

  </div>
 </div>

</g:HTMLPanel>
</ui:UiBinder>


Two important things to notice here:
  • For YUI Widgets we are writing using the same markup as expected and documented by YUI Widgets. For example, we give a plain html element <button> for creating a YUI Button, and give the markup documented in TabView Documentation - Minimal markup required.
  • We want to bind with GWT UIBinder the html elements corresponding to a YUI Widget, so we annotate them with ui:field="myfield".
  • Each html element corresponding to a YUI Widget must be annotated with an special class name corresponding to the aforementioned Widget. For example we annotate indicate it is a YUI Button using class="yui-button". This is how we indicate "this element must be rendered as a YUI Button"



And now the Java Sources corresponding to the UIBinder Composite definition I hope it is self documented:

package org.sgx.yuigwt.ui.test;

import org.sgx.yuigwt.ui.YUIBinder;
import org.sgx.yuigwt.ui.YUIBinderListener;
import org.sgx.yuigwt.yui.YuiContext;
import org.sgx.yuigwt.yui.event.EventCallback;
import org.sgx.yuigwt.yui.widget.button.Button;
import org.sgx.yuigwt.yui.widget.button.ButtonEvent;
import org.sgx.yuigwt.yui.widget.tabview.TabView;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;

/**
 * this is a common UIBinder Composite class. Notes:
 * 
 * < p>
 * 1) for YUI, we are binding plain HTML Elements, like @UiField Element
 * tabViewEl1;
 * < /p>
 * 
 * < p>
 * 2) then in the constructor, after this GWT widget is initialized with
 * initWidget(uiBinder.createAndBindUi(this));, we call YUIBinder.bindYUI
 * passing this Element UIFields corresponding to YUI stuff and register myself
 * as a listener to be notified when YUI binding is done to start working.
 * < /p>
 * 
 * < p>
 * 3) in yuiBinded() callback we ask for YUI Widgets and start working with
 * them.
 * < /p>
 * 
 * @author sg
 * 
 */
public class YUIInUiBinderTest2 extends Composite implements YUIBinderListener {

 interface MyUiBinder extends UiBinder< Widget, YUIInUiBinderTest2> {
 }

 private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);

 @UiField
 Element tabViewEl1;

 @UiField
 com.google.gwt.user.client.ui.Button gwtButton1, gwtButton2;

 @UiField
 Element yuiButtonEl1;

 @UiField
 Element yuiButtonEl2;

 private YUIBinder binderUtil;

 private Button yuiButton1;

 private TabView tabView;

 public YUIInUiBinderTest2(YuiContext y) {

  initWidget(uiBinder.createAndBindUi(this));

  binderUtil = new YUIBinder();

  /*
   * bind YUI stuff manually passing this Element UIFields corresponding
   * to YUI stuff and register myself as a listener to be notified when
   * YUI binding is done
   */

  binderUtil.bindYUI(y, this, new Element[] { tabViewEl1, yuiButtonEl1, yuiButtonEl2 }, this);

  /*
   * the gwt widgets can be used right away, but for using YUI widgets we
   * need to wait until binding is finished, see method yuiBindede() below
   */
  gwtButton2.addClickHandler(new ClickHandler() {
   @Override
   public void onClick(ClickEvent event) {
    Window.alert("gwtbutton1clicked");
    tabView.selectChild(2);
   }
  });
 }

 @Override
 public void yuiBinded() {
  /*
   * all YUI stuff is ready and rendered, we obtain the YUI widgets and
   * work directly in java:
   */
  yuiButton1 = binderUtil.getWidget(yuiButtonEl1).cast();
  tabView = binderUtil.getWidget(tabViewEl1).cast();

  yuiButton1.on("click", new EventCallback< ButtonEvent>() {
   @Override
   public void call(ButtonEvent e) {
    tabView.selectChild(1);
   }
  });
 }

}

Interesting stuff here:

  • Unlike GWT widgets, for work with YUI Widgets we will bind plain HTML Element (com.google.gwt.dom.client.Element).
  • We need to manually call our "YUIBinder", passing all the @UIField Elements correspondiing to YUI widgets and later, when the binding is dont, we can obtain the YUIGWT Widget classes to work with them in Java.

Known Issues

  • Some GWT Widgets are not designed to contain any HTML content only other GWT widets, so it is possiblt that including YUI Widgets there cannot behave well.
  • Putting a GWT Button inside a YUI TabView will make the GWT button to loose click handlers... ?

How this works and some decisions.

lunes, 15 de octubre de 2012

Testing GWT Service Classes synchronously using syncproxy

Testing GWT Service Classes synchronously using syncproxy


Why ?


In GWT applications that use RPC for client-server comunication, RPC "Services" classes bring a Web API to our business logic core in the server. For example, an RPC service class may be responsible of managing a certain model class (its CRUD operations, etc). It is important for us to write automated tests for ensuring a certain degree of quality of those RPC services, automatically.

In a common - not GWT application we just write Junit serverside tests that will use our services classes asynchronically. For example, a service for a managing Apples, could be easily tested with the code:

Apple a1 = new Apple(); 
a1.setId("a1"); 
a1.setColor("red"); 

appleService.addApple(a1); 
Apple a2 = appleService.getAppleByName("a1"); 
assertEquals("red", a2.getColor()); 

appleService.removeApple(a1); 
a2 = appleService.getAppleByName("a1"); 
assertTrue(a2 == null); 

Unfortunately, GWT RPC service class methods, are called asyncrhonously, so it is very hard to write the same test case, because, we need to"continue the next test " inside the (async) callback. So for writing  the last example using RPC async calls, we will end up with code that contains 4 or 5 anidated code blocks, like:

appleService.addApple(a1, new AsyncCallback<Void>() {

 @Override
 public void onSuccess(Void result) {

  appleService.getAppleByName("", new AsyncCallback<Apple>() {

   @Override
   public void onSuccess(Apple result) {
    assertTrue(result.getColor().equals("red"));

    // :( ... test folows here ... :(
   }

   @Override
   public void onFailure(Throwable caught) {
   }
  });
 }

 @Override
 public void onFailure(Throwable caught) {
 }
});

On a first thought I tried to remedy this using a datastructure I called SyncQueue, for putting each service method call in a queue and at the end, ask the sync queue to run each task synch. But as this example shows, this is also a not so productive and readable way of writing tests.

How to ? 


Thinking this for some time get me to the conclusion that I really need to write JUnit test calling my RPC service methods synchronously (like the first code example). The project syncproxy seemed what I wanted but it wasn't so trivial to getting started with, mainly because documentation seems a little outdated.

So these are my instructions for making synch tests of your RPC services, using eclipse and google eclipse  plugin.

A summary of the entire procedure:
  1. create a new GWT Application project using eclipse New Application project wizard code template that comes with an example RPC service to test against to. This will be our "target" GWT application which we want to test.
  2. create a (second) eclipse Java Project, add syncproxy.jar and previous "target" GWT project to its build path. 
  3. create a JUnit  TestCase class in the test project that calls the target service class synchronously. The test app is a java client that tests against the "target" running GWT application.

First of all, I suppose you already have a GWT application which GWT services you wish to write tests for. If you don't just create a new GWT Web Applicaiton project with asking the wizard to create the template project that contains an already running RPC service for testing. That is what we will use in this example, so

Step 1 (optional): create a GWT project with a RPC service to test. 

Go to File -> New -> Other... -> Google -> Web Application Proje. Unselect Support for appengine and make sure "Generate sample code" is checked: 




Press Finnish and test the new application if you want. In my case I named it "Gwtrpcapp1" so I right click the file /war/Gwtrpcapp1.html -> Debug as .. -> Web Application . After is loaded, open the url http://127.0.0.1:8888/Gwtrpcapp1.html?gwt.codesvr=127.0.0.1:9997 in your browser.

This project cointains a RPC service called "greet". The data that we need from this RPC service are its module base url ("http://127.0.0.1:8888/gwtrpcapp1/") and the name of the service that we wish to test ("greet"). I found these values using Firefox's Firebug extension for examining HTTP request of our app:


Step 2: Create your test project


We will create a second project containing our junit tests. We choose a second project but if you are familiar with the tools you should not have major problems for putting these tests inside the same GWT project. In this case go to File -> New -> Java -> Java Project and create one. In my case I named it "Gwtrpcapp1Test1".

Now let's configure it a little this new project, first of all add the our target GWT project to its java class path. Right click project "Gwtrpcapp1Test1" -> Build Path -> Configure build Path -> Projects -> Add.. and choose our  target in my case "Gwtrpcapp1".

Also download syncproxy.jar from http://code.google.com/p/gwt-syncproxy/downloads/list,. copy syncproxy.jar file inside project "Gwtrpcapp1Test1", and add it to its class path.

Also you will need to add gwt-servlet.jar to your test project build path. Just go to Configure build path -> Libraries -> Add jars and choose the file  gwtrpcapp1/war/WEB-INF/lib/gwt-servlet.jar.


Now create some java package to work and create a Junit Test right clicking the package -> New .. -> Other -> Java -> JUnit -> JUnit Test Case. Eclipse will ask permission for adding JUnit library in your project. Complete some simple test there:

package org.sgx.gwtrpcapp1.test;

import static org.junit.Assert.*;

import org.junit.Test;
import org.sgx.gwtrpcapp1.client.GreetingService;

import com.gdevelop.gwt.syncrpc.SyncProxy;
/**
 * test for GreetingService - url : http://127.0.0.1:8888/gwtrpcapp1/greet 
 * @author sg
 *
 */
public class GreetingServiceTest1 {
 private static final String MODULE_BASE_URL = "http://127.0.0.1:8888/gwtrpcapp1/";
 private static final String SERVICE_NAME = "greet"; 
  
 private static GreetingService greetingService = (GreetingService) SyncProxy
  .newProxyInstance(GreetingService.class, MODULE_BASE_URL, SERVICE_NAME);

 @Test
 public void test() {
  System.out.println(greetingService.greetServer("Sebastian"));
  assertTrue(greetingService.greetServer("Sebastian").startsWith("Hello, Sebastian!"));    
 }
}

Important:  For this to work, all the classes that you want to pass / return from RPC methods must implement the com.google.gwt.user.client.rpc.IsSerializable interface.

 Run the test


If everything was fine, first run the target GWT Application like I told you before, and after its loads complete, run the our JUnit test. For that just right click GreetingServiceTest1 file -> Run as -> JUnit Test Voila! Hope this can be helpful to others in a similar situation.

Google AppEngine DataStore

If you are testing RPC services that perform some CRUD operations in Google Appengine DataStore these few tips could be helpful. Also this apply for frameworks that run on top of appengine datastore, like objectify.

The datastore it self is not synchronically: it takes some seconds to really impact changes to the datastore. So for example, if in our synchronous JUnit tests we save an entity it could not be available yet in the next data query. The same for deletion, it takes aprox 5 seconds to the datastore to really impact the entity deletion.

This is bad for our synchronous JUnit tests where we want the changes to impact synchronously. Fortunately, it is easy to configure the appengine in devmode for the datastore to behave synchronously. Just go to your appengine project launch configuration -> Appengine and edit the "unapplied job percentage" value to a very small number like 0.001:

Now your datastore will behave synchronously (at least almost all the time).

Also, I successfully run this test against my application deployed on appspot.com. I thought the test will fail because the weak consistence nature of the datastore, but surprisely, the test finnish without errors. Coud this be because of my slow intenret connection. Or, more worry, could this be because my eclipse application launcher configuration is somehow deplyed also ? ... mmm will have to investigate...

miércoles, 10 de octubre de 2012

Developing a vaadin application for Google appengine in eclipse.

Developing a vaadin application for Google appengine in eclipse. 


This is a step by step tutorial about making a vaadin application that runs on top of google appengine.

vaadin supports google appengine as a server backend as it is documented in the vaadin book. Also the vaadin eclipse plugin comes with a eclipse project wizard for building a web application based on vaadin and GAE. However, the resulting application do not support the GAE runtime and as a result, the GAE developemtn mode cannot be used (for testing the GAE application locally before deploying it to the web).

In this tutorial, we will generate such an application and change it for supporting GAE runtime and so being able of testing the app locally. The idea is to do agile development (save a file change, and only need to refresh the web page for reflecting the changes, no server restart)

So let's begin, we will use eclipse 4.2, java 1.6, Google appengine (GAE) 1.7.1, vaadin 6.8.4. OS: linux . Also this has been tested on eclipse 3.7.

1) Install Google Plugin for Eclipse. You can use eclipse marketplace at Help -> Marketplace for easy find and install this plugin.

2) Install Vaadin Plugin for Eclipse. You can use eclipse marketplace at Help -> Marketplace for easy find and install this plugin.

3) Create a new vaadin project. Just go to File -> New -> Other -> Vaadin -> Vaadin project. Make sure you set "Deployment configuration" to "Google App Engine servlet". You can leave all the other options to their default values. For this example, we left "Create project template" checked because we want something to test right away.

Also notice that we leave the target runtime empty: we don't want to run this application on tomcat or some other Java container but using the GAE runtime. In this example we named the project "vaadingaetest".  This project is ready for being deployed on GAE, but we cannot use the GAE runtime locally for testing and working, that is what the following steps are for.





4) Edit the project's .project file. You may need to go to eclipse's Navigator view for locating it because it is hidden in most other views. Once you have opened it, we need to add the XML element com.google.appengine.eclipse.core.gaeNature inside the element. you should end with something like this:
<natures>
 <nature>com.google.appengine.eclipse.core.gaeNature</nature>
 <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
 <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
 <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
 <nature>org.eclipse.jdt.core.javanature</nature>
 <nature>com.vaadin.integration.eclipse.widgetsetNature</nature>
 <nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>


5) Enable the GAE runtime in the project. This is simply a matter of adding the GAE library to the project. Right click on the project name in the project explorer -> Build Path -> Add Libraries and there choose "google app engine" and use the default SDK. If you have not an GAE SDK installed, install it (you can ask eclipse to download it for you). Also you may need to give the GAE library more preference than other libraries. Just right click the project -> Build path -> Configure build path -> Order and export and there select the "appengine SDK" entry on the list and press the Up button for increasing the priority of this library like showed on the following image:



6) Fix the file war/WEB-INF/appengine-web.xml adding the following element inside. For some reason this geerated file won't work without that line.

true

And that's all the configuration needed! Now let's run our vaading application using the GAE runtime locally.

7) Run our vaadin application on GAE runtime. For this, make sure you have refreshed the project and then right click the project name -> Debug As -> Web Application. Note: if there is no Web Application option this means you have done something wrong in steps 4 or 5. Try to refresh your project and make sure you are working in Java Porject Explorer eclipse view.

8) Test your application, open http://localhost:8888/?restartApplication in your browser and you should see your vaadin app. Now, let's modify something on file /vaadingaetest/src/com/example/vaadingaetest/VaadingaetestApplication.java, for example, change the label value like:

Label label = new Label("Hello Vaadin eclipse and appengine user!");

Save the java file and you should see your changes reflected just refreshing your browser window with F5 key.

A little explanation: In a vaadin application we do not have jsps or html pages, but servlets that are responsible for render our app. Because in the project creation wizard we left "Create project template" checked, the wizard has created a sample application for us that we can run and in our case this servlet class is com.example.vaadingaetest.VaadingaetestApplication. Also looking at the created web descriptor (file /war/WEB-INF/web.xml) we can see that the servlet is mapped to the URL pattern "/*", this means accessing http://localhost:8888/anythinghere will render our vaading application (a servlet).

Also, notice that I used the ?restartApplication http parameter. This tells vaadin framework to automatically apply changes in the java code without having to restart the container something very appreciated when developing.


Well, hope this can serve others eclipse vaading and google app engine users to getting started with these technologies.