Home » Featured, GWT, Nokia WRT

Mobile Widgets with GWT with Spring and JSONP

9 March 2010 6,365 views 4 Comments
View Daniel Vaughan's LinkedIn profileView Daniel Vaughan’s profile
Over the past couple of weeks I have been looking at the feasibility of creating mobile widgets using Google Web Toolkit (GWT).  Mobile widgets package up open web technology, specifically HTML, CSS, JavaScript files in such a way that they can be deployed as  applications on mobile phones.  In a similar way the same files could be packaged to deploy as Opera widgets or Adobe Air applications. The productivity gain of writing code once like this and being able to execute it on so many platforms is very appealing especially for developers who have to target multiple mobile platforms.

A GWT solution

The programming language I am most comfortable with is Java and for web application I have been using GWT extensively for the last couple years. GWT compiles Java into optimised, cross-browser JavaScript. This has a number of advantages some of the most important of which are the ability to debug and test code using the wide range of Java based tools.

With this in mind I thought GWT would be the ideal tool for ideal for creating a JavaScript application to package up into a mobile widget. I set off making a proof of concept last week. The proof of concept, based on a standard GWT example application was successful and with a few tweaks I was quickly able to deploy a GWT based mobile widget, in that case a Nokia Web Runtime (WRT) widget, to my Nokia E72 mobile phone.

One of the great features of GWT however is the ability it gives to JavaScript to communicate with backend Java services via a mechanism called GWT RPC. In the work I do this is very useful as there are  plenty of Java based backend services that need to be accessed. This mechanism works by the client (JavaScript) code and the server (Java) code being deployed together in the same war file and in the web container. However, when the JavaScript alone is packaged up in a widget the web container is not there and so there is nowhere for the server Java code to run. This means that in the case of widgets I had to look at a different way of communicating with the server.

Since server calls from a mobile client will be going across a relatively slow and unreliable 3G or worse mobile connection I wanted to keep the mechanism as light weight as possible. Using simple REST services with JSON data seemed like a good approach. However the JavaScript that calls the service would be in a mobile widget effectively running on a local server on the mobile phone. The JSON service would be on a remote server and this will cause cross-site scripting issues due to the same origin policy.

This led me to look at JSONP (JSON with padding). JSONP allows you to pad the JSON data that is returned from the server with a JavaScript callback function.  This means that when the response comes back from the server the callback function is called on the client to do something meaningful with the data. As the call is performed within a script tag the same origin policy does not apply and so the client can consume the service residing on the remote server.

How to implement it

I wanted to make this work using GWT for my client and Spring as the framework for the server services. Looking on the web there were lots of articles about JSON with Spring, GWT with JSON and I even found a couple that had GWT, Spring and JSON together.

GWT and Spring move very quickly and pretty much everything  even articles that were a few months old were out of date or at least in the latest version of Spring or GWT there seemed to be a better way of doing something.  It always starts to get worrying when you see questions in forums that are relevant to what you are trying to do and then realising they are only one or two weeks old.

It was a bit of a struggle to break everything down and work out the simplest way to achieve my objective; making a JSONP request in GWT 2.0.2 to a remote service based on Spring 3.0 MVC and using the facilities available. Even then I had to take anything I produced one stage further by packaging the resultant GWT generated JavaScript as a mobile widget. I therefore decided to share my solution in the hope that others will be able to improve upon it. Please bear in mind that Spring MVC especially version 3.0 is still very new to me and as such I would appreciate any feedback.

The first thing I did was to follow the making cross-site requests tutorial in the web toolkit documentation. This uses Python or PHP on the server and does not use the most current GWT features for a JSONP call but it is GWT using JSONP.  I went through it and packaged up the resultant GWT generated JavaScript code into a mobile widget. The widget successfully installed on my Nokia E72 phone and I was able to confirm that what I wanted to do was possible. The phone made the JSONP service and data was returned.

Knowing that what I wanted to do was theoretically possible I set about making a proof of concept to using Spring one the server and prove that it was possible to make a JSONP request from GWT and get the correct response back while keeping code to a minimum. To keep it really simple all I wanted to achieve was to receive a person object with my name “Dan” back from the server.

Part 1 – Server side

Dependencies

I use maven for my dependency management so setup my pom to include the following packages:

Package Version
spring-core 3.0.1.RELEASE
spring-context 3.0.1.RELEASE
spring-webmvc 3.0.1.RELEASE
com.springsource.org.codehaus.jackson.mapper 1.4.2
servlet-api 2.5
log4j 1.2.15

The Domain

All that I wanted to do was get back a Person object from the server containing my name so ss I wanted to keep this as straight forwards as possible I defined the Person object as a simple bean.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.danielvaughan.examples.jsonp.domain;

public class Person
{
private final String name;

public Person(String name)
{
this.name = name;
}

public String getName()
{
return name;
}
}

The Controller

The controller is almost as simple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.danielvaughan.examples.jsonp.server.web;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.danielvaughan.examples.jsonp.domain.Person;

@Controller
@RequestMapping(value = "/person/**")
public class PersonController
{
@RequestMapping(method = RequestMethod.GET, params="callback")
public void getPerson(ModelMap modelMap)
{
Person person = new Person("Dan");
modelMap.addAttribute("person", person);
}
}

Here I am using Spring annotations. The @Controller annotation marks my class as a MVC Controller and the @RequestMapping annotation for the class tells it to accept requests on the person path.

The @RequestMapping on the getPerson() method tells it to respond to HTTP get requests that have the callback parameter set. This means that the URL for calling this from a browser would look like this: /person?callback=<some JavaScipt method name>.

The method creates a new person with the name “Dan” and adds it to the modelMap with the key person.

Adding a custom view resolver

In Spring 3.0 the MappingJacksonJsonView is included for providing a JSON view of a response to a request.  However, at the time of writing there is not a built in view that can provide me with what I want which is JSONP padding of the JSON view so as a quick solution until I work out a better one I just took a copy of the MappingJacksonView and modified the renderMergedOutputModel method to create my own MappingJacksonJsonpView.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception
{
Object value = filterModel(model);
JsonGenerator generator = objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), encoding);
String callback = request.getParameter("callback");
if (callback!=null)
{
prefixJson = true;
}
if (prefixJson)
{
generator.writeRaw(callback + "(");
}
objectMapper.writeValue(generator, value);
generator.flush();

if (prefixJson)
{
generator.writeRaw(");");
generator.flush();
}
}

All I have done is to take the value of the callback parameter given in the request and use that to pad the generated JSON.  If anyone has a less messy way of doing this such as a servlet filter I would like to hear from you.  In the meantime I will work out a more permanent solution.

Web configuration

I now need to create my web.xml (src\main\webapps\WEB-INF\web.xml).

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>JSONP Example</display-name>
<display-name>A simple example of serving JSONP</display-name>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>
classpath:log4j.properties
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!-- required to enable Spring 3.0 REST support -->
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<servlet-name>jsonp-example</servlet-name>
</filter-mapping>
<!-- Servlets -->
<servlet>
<servlet-name>jsonp-example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jsonp-example</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
</web-app>

All I am doing here is defining my servlet.

Spring configuration

In my jsonp-example-servlet.xml (src\main\webapps\WEB-INF\jsonp-example-servlet.xml) I have the following:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<!-- Sets up all handlers automatically and configures conversion services including Jackson if in classpath  -->
<mvc:annotation-driven />
<!--  scans the base package looking for @Controllers etc to setup automatically -->
<context:component-scan base-package="com.danielvaughan.examples.jsonp.server.web" />
<!--  adds a view for presenting the results of a request in JSON format  -->
<bean>
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean/>
</list>
</property>
<property name="viewResolvers">
<list>
<bean />
</list>
</property>
</bean>
</beans>

From what I can work out this is the minimum I need to get Spring to setup the correct handlers, pick up my annotations and wire everything together for me.  In the view resolver bean I tell spring to encode the response as the application/json MIME type and to use my MappingJsonpView view.

Now everything is in place and I just put the following URL in a browser which specifies the callback function as “myCallback”:

http://127.0.0.1:8080/examples-jsonp/service/person?callback=myCallback

I should  get a JSONP encoded person object with the name “Dan”, the desired result:

1
myCallback({"person":{"name":"Dan"}});

That is all I want to do on the server side. Now I will look at the GWT client.

Part 2 – The Client

Now I have a server with a service that will respond to JSONP requests I want to create a GWT client that will call the service and process the results. Again this is going to be as simple as possible. All I really want it to is perform the request and display my name in the browser.

I create a new GWT 2.0.2 project and remove pretty much all the GWT boiler plate code. In GWT JSONP support is a separate module called com.google.gwt.jsonp.Jsonp so I need to specify it in my gwt.xml . My gxt.xml file looks like this:

<?xml version=”1.0″ encoding=”UTF-8″?>
<module rename-to=’examplejsonpclient’>
<!– Inherit the core Web Toolkit stuff.                        –>
<inherits name=’com.google.gwt.user.User’ />
<!– Other module inherits                                      –>
<inherits name=’com.google.gwt.jsonp.Jsonp’ />
<!– Specify the app entry point class.                         –>
<entry-point class=’com.danielvaughan.examples.jsonp.client.ExampleJsonpClient’ />
<!– Specify the paths for translatable code                    –>
<source path=’client’ />
</module>

My html file and web.xml are absolutely minimal. In my EntryPoint class, ExampleJsonpClient, I add the following to the onModuleLoad() method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void onModuleLoad()
{
final Label label = new Label();
RootPanel.get().add(label);

String url = "http://127.0.0.1:8080/examples-jsonp/service/person";
JsonpRequestBuilder jsonp = new JsonpRequestBuilder();
jsonp.requestObject(url, new AsyncCallback
()
{
public void onFailure(Throwable throwable)
{
label.setText("Error: " + throwable);
}

public void onSuccess(Person person)
{
label.setText("Hello " + person.getName());
}
});
}

When I run the GWT application I get what I wanted in the browser:

Hello Dan

Part 3 – The mobile client

Now to make this into a mobile widget. All widget implementations seem to vary slightly regarding how the packaging is done but as I have a Nokia mobile phone I am going to package my widget as a Nokia WRT widget. It is my understanding that Opera WidgetsAdobe Air and iPhone Apps (via PhoneGap or Appcelerator) and widgets for other platforms can all be packaged in a similar way the only differences usually being the extension of the zip file and the format of the configuration file.

Putting the spring service on the web

First however I  need to package up the spring project into a war file and deploy it somewhere that our mobile phone will be able to access such as a public facing web container like Apache Tomcat or a JEE server if you have access to one.

Another good place for services like these would be a cloud based service such as Amazon EC2 using something like Spring Source’s CloudFoundry. It is likely Google App Engine would also be suitable for many applications and certainly would have no trouble for this one with a right setup.

Whatever then I need to update the URL referenced in the onModuleLoad method of our GWT apps’ EntryPoint class to point at the URL of the deployed Spring service rather than the one running on the local host.

Minimising the number of files

As I want to minimise the size of the application I deploy to the mobile it is a good idea to setup the GWT compiler so that it produces the JavaScript only for the  target browser and not other browsers such as IE, Firefox etc. Since the browser on my Nokia phone is based on WebKit I only want output that is optimised for that browser so I add the following like to the gwt.xml file:

<set-property name="user.agent" value="gecko"/>

Compiling the GWT app now leaves us with far fewer files to our mobile widget with. It is also a good idea that the output style is set to Obfuscated for the smallest file size.

Packaging as a mobile widget

To package the project as a WRT widget I now need to create a file called Info.plist that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Nokia//DTD PLIST 1.0//EN" "http://www.nokia.com/DTDs/plist-1.0.dtd">
<plist version="1.0">
<dict>
<key>DisplayName</key>
<string>ExampleJsonpClient</string>
<key>Identifier</key>
<string>com.danielvaughan.examples.jsonp.client.ExampleJsonpClient</string>
<key>Version</key>
<string>1.0</string>
<key>AllowNetworkAccess</key>
<true/>
<key>MainHTML</key>
<string>ExampleJsonpClient.html</string>
<key>MiniViewEnabled</key>
<false/>
</dict>
</plist>

The important bits are the AllowNetworkAccess part which unsurprisingly lets the application connect to the internet and setting the MainHTML value to the GWT apps html file ExampleJsonpClient.html.

Now I  compile my GWT project take war\examplejsonpclient folder, ExampleJsonpClient.html and Info.plist and add them to a zip file. I name the zip file ExampleJsonpClient.wgz. The wgz extension is important as this is what identifies it as a mobile widget.

Deploying

Now all I need to do is transfer the ExampleJsonpClient.wgz file to my mobile phone. I just send it as a Bluetooth message. When I open the message I am prompted to install the widget and then I have an application I can run.

One running the application I get a blank screen with the same message as I had in my web browser:

Hello Dan on a Nokia E72

Source code

The source code for this application is available here:
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...

4 Comments »

  • Daniel Vaughan.com » New Article on Mobile Widgets using GWT, Spring and JSONP said:

    [...] After looking at how Google Web Toolkit could be used to produce mobile phone applications I have written up an article here: http://www.bristol-gtug.org/?p=76 [...]

  • mschmitt said:

    You said:
    > The JSON service would be on a remote server and this will cause cross-site scripting issues due to the same origin policy.

    i implemented a WRT solution with GWT also last week. With WRT the installed WGZ file runs in local file browser context. There is no problem with the same origin policy.

    Instead there is a problem with the RPCRequestBuilder and the validation of the incoming request, where i had provide a workaround by validation only through the “strongname”.

  • Daniel Vaughan (author) said:

    Thanks, since writing this I have suspected that SOP is a non-issue on WRT too. I have been also looking at PhoneGap for the iPhone and realised it was not a problem there for the same reason and so was going to go back to WRT to verify it worked in the same way.

    In your WRT GWT solution have you been using any of the WRT JavaScript API (for menus, GPS etc.)? I have wrapped a lot of the WRT API for GWT and now and will publish on Google Code if it is useful to others or if others want to improve and add to it.

  • mschmitt said:

    I only wrapped the GPS access.

    i didn’t use WRT Widgets, Views or UIManager,
    but used gwt-presenter and my own GUI elements instead.

    My goal was to use my browser application inside of WRT as much as possible.

Leave your response!

Add your comment below, or trackback from your own site. You can also subscribe to these comments via RSS.

Be nice. Keep it clean. Stay on topic. No spam.

You can use these tags:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

This is a Gravatar-enabled weblog. To get your own globally-recognized-avatar, please register at Gravatar.