Creating iPhone webapps with Vaadin Touchkit

In this post I’d like to write down my experiences (so far) with creating iPhone webapps with Vaadin TouchKit. For those of you who are not familiar with TouchKit:

TouchKit is a tool kit that lets you develop applications that look and feel like native iPhone applications using only Vaadin.

That means in plain English: Creating iPhone webapps in pure Java with a GWT-based, elegant web framework and no HTML, JavaScript or other technology required.

Vaadin provides an Eclipse plugin, which is the recommended way of developing a Vaadin application, but that would only be half the fun. I want to go two steps further:

  • Use Maven as build / project management tool – but still using Eclipse as IDE.
  • Use Google Appengine as hosting environment.

I wrote already about mavenizing a Google Appengine project.

Create a Vaadin Maven project

  1. Vaadin already has a good Maven plugin. For TouchKit it is required to have the option to compile the Vaadin widgetset. Therefore we use the Maven archetype to create a project which includes the GWT plugin already:
    
    mvn archetype:generate \
    -DarchetypeGroupId=com.vaadin \
    -DarchetypeArtifactId=vaadin-archetype-sample \
    -DarchetypeVersion=LATEST \
    -DgroupId=your.company \
    -DartifactId=project-name \
    -Dversion=1.0.0 \
    -Dpackaging=war
    
  2. Optional: run the application with mvn jetty:run. You can access the application at localhost:8080/project-name
  3. Optional: Create the Eclipse project files to import the project in Eclipse with mvn eclipse:eclipse. Of course this is not required, and instead of Eclipse you can use your IDE of choice.
  4. The created pom.xml file doesn’t reference the latest versions of Vaadin and GWT, unfortunately. For TouchKit at least Vaadin 6.3 is required. Therefore change Vaadin to version 6.3.0 and GWT to version 2.0.3:
    
    <dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>vaadin</artifactId>
    <version>6.3.0</version>
    </dependency>
    <!-- This is also used by gwt-maven-plugin to deduce GWT version number. -->
    <dependency>
    <groupId>com.google.gwt</groupId>
    <artifactId>gwt-user</artifactId>
    <version>2.0.3</version>
    <scope>provided</scope>
    </dependency>
    

Add the TouchKit widgetset

  1. Add the TouchKit dependency to the classpath:
    
    <dependency>
    <groupId>org.vaadin</groupId>
    <artifactId>vaadin-touchkit</artifactId>
    <version>0.5</version>
    </dependency>
    
  2. Unfortunately, TouchKit is not available in a public Maven repository. You have two choices now: either add the TouchKit jar to your local repository using mvn install:install-file or you put it into your own remote repository. The advantage of the second option is obvious: you don’t need to install the file on all your development machines locally. Add your remote repository to pom.xml:
    
    <repository>
    <id>cloudme</id>
    <url>http://cloudme.googlecode.com/svn/maven</url>
    </repository>
    
  3. Update web.xml file and change the servlet class to org.vaadin.touchkit.mobileapplication.MobileApplicationServlet, as described here.
  4. Unfortunately, there is a bug in the current gwt-maven-plugin, and therefore a workaround is required to use the TouchKit widgetset: create your own widgetset which inherits TouchKit. It is important to set the entry point, otherwise the Maven plugin will not compile it correctly:
    
    <module>
    <entry-point class="com.vaadin.terminal.gwt.client.DefaultWidgetSet" />
    <inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet" />
    <inherits name="org.vaadin.touchkit.widgetset.TouchKitWidgetset" />
    </module>
    
  5. Change the widgetset in web.xml:
    
    <init-param>
    <param-name>widgetset</param-name>
    <param-value>com.example.gwt.MyWidgetset</param-value>
    </init-param>
    

Now create a simple application using TouchKit widgets as described here, update the application parameter in web.xml and perform a clean build: mvn gwt:clean jetty:run

Enable Google Appengine

Please note that the following steps describe only the basic, most necessary steps required to run the TouchKit application in Google Appengine.

  1. Add the GAE version to the properties section of the pom.xml:
    
    <gae.version>1.3.2</gae.version>
    
  2. Add required plugins:
    
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1-beta-1</version>
    <configuration>
    <webResources>
    <resource>
    <directory>src/main/webapp</directory>
    <filtering>true</filtering>
    <includes>
    <include>**/appengine-web.xml</include>
    </includes>
    </resource>
    </webResources>
    </configuration>
    </plugin>
    <!--
    The actual maven-gae-plugin. Type "mvn gae:run" to run project,
    "mvn gae:deploy" to upload to GAE.
    -->
    <plugin>
    <groupId>net.kindleit</groupId>
    <artifactId>maven-gae-plugin</artifactId>
    <version>0.5.7</version>
    </plugin>
    <!--
    Upload application to the appspot automatically, during
    release:perform
    -->
    <plugin>
    <artifactId>maven-release-plugin</artifactId>
    <configuration>
    <goals>gae:deploy</goals>
    </configuration>
    </plugin>
    
  3. And, of course, the plugin repository:
    
    <pluginRepository>
    <id>maven-gae-plugin-repo</id>
    <name>maven-gae-plugin repository</name>
    <url>http://maven-gae-plugin.googlecode.com/svn/repository</url>
    </pluginRepository>
    
  4. Create a appengine-web.xml file in WEB-INF:
    
    <appengine-web-app
    xmlns="http://appengine.google.com/ns/1.0">
    <application>project-name</application>
    <version>1</version>
    </appengine-web-app>
    

Now you can run the application with mvn gae:run

Mavenizing my project

I started working on a Google App Engine project the usual way: using the Eclipse plugin. However, unfortunately the update to the latest Eclipse plugin broke it and I haven’t found a fix yet. So I decided to try the maven-gae-plugin, once again; with Maven everything runs builds better anyway, right? So far I had only made some minor tests with the plugin.

Setup

For mavenizing the project I went the safe route: I created a new project with the maven archetype plugin:


mvn archetype:create\
 -DarchetypeGroupId=net.kindleit\
 -DarchetypeArtifactId=gae-archetype-gwt\
 -DarchetypeVersion=0.5.0\
 -DgroupId=your.groupId\
 -DartifactId=your-artifactId\
 -DremoteRepositories=http://maven-gae-plugin.googlecode.com/svn/repository

The project itself was only temporary, I was interested in the pom.xml file. I updated that file accordingly (e.g. the plugin version of the file was not the latest), removed GWT sections as I don’t use GWT in my project and changed some minor settings and added all required dependencies. Finally I copied the pom.xml into my project directory.

Subversion trouble

Then I made a lot of modifications within Eclipse – moved sources to standard Maven locations, removed JAR files etc. and was about to commit everything – but unfortunately Subversion detected a bunch of tree conflicts. Bummer. While resolving these conflicts seem to be hard, I decided to check out the project into another directory and start changing the structure from scratch – this time not using Eclipse but Subversion command line tools. That worked perfectly.

Running

With running mvn gae:run I started the development server. Startup was really smooth. However, by default the server is started on localhost only, but in my project I need a specific IP address as I need to access the server from the iPhone, too. Therefore I had to set the gae.address property. Of course it can be defined in pom.xml, but then it is the same for all development machines. I don’t want that. Therefore it must be defined in the users’s ~/.m2/settings.xml:


  <profiles>
    <profile>
      <id>gae</id>
      <properties>
        <gae.address>192.168.178.24</gae.address>
      </properties>
    </profile>
  </profiles>
  <activeProfiles>
    <activeProfile>gae</activeProfile>
  </activeProfiles>

Now the server runs on the right IP address.

Debugging

Now with using Maven I did not want to get rid of the ability to debug my application. How can this be done? Easy. First of all, the plugin provides the mvn gae:debug goal. When running this goal, the development server starts in debug mode.

In Eclipse a new run debug configuration has to be created.

  1. In the Console run mvn gae:debug; Maven will compile, execute tests and start the development server in debug mode.
  2. Wait until the server waits for the remote debugger; you will see the following output: “Listening for transport dt_socket at address: 8000″. The address is in this case the port, which needs to be set in the Eclipse debug configurations.
  3. In Eclipse go to Run > Debug Configurations …
  4. Create a new “Remote Java Application” configuration
  5. Give it a good name, choose Connection Type “Standard (Socket Attach)” and set the Connection Properties (in my case Host: 192.168.178.24, Port: 8000)
  6. Click on “Debug”. Now you see that the development server in the console continues.

Reloading webpages

Now everything works as good as when using the Eclipse plugin, right? Not quite. There is one thing that doesn’t work: dynamic reload of webpages, such as JSP or CSS files. Jetty allows dynamic reload, but when using Maven, Jetty does not use the src/main/webapp folder as working directory; instead it uses its own directory somewhere in target/…

To avoid long edit / build / deploy / run cycles, the recommended way at the moment is to run mvn gae:run in one console window and mvn cli:execute in another window. The command line interface allows you to quickly execute Maven goals. Run compile war to update the webpages in the development server’s working directory.

While this is not quite as simple as with Eclipse, it is a workaround that speeds up the development process significantly.

First run Maven GAE Plugin

Until now I used the Eclipse plugin to develop and test Google App Engine applications. Today I tried the Maven GAE Plugin, in order to become more flexible and independent from Eclipse. My first observations were:

  • As I started with the Maven GAE Archetype, the package declaration of the generated code did not match the actual file location. That needed to get corrected first.
  • I changed the compiler settings from 1.6 (default settings of the archetype) to 1.5 and had to remove some @Override annotations.
  • The gae.home property is undefined (which makes sense), but I had to define it to run the development server.

Overall, I’m quite pleased with the first run. Although Maven adds a lot of overhead, and the actual build process took a bit too long initially to download all dependencies, the overall impression is very good.

Upgrading Maven on Mac OS X

Upgrading Maven on Mac OS X is generally nothing very special, but I’d like to summarize the steps I’ve done. Maybe it is helpful for users which are not so familiar with the Terminal application.

terminal_app

  1. First of all: start the Terminal application, located in the folder /Applications/Utilities/Terminal.app.
  2. Here you can find out which Maven version is currently running, by typing mvn -version. You will get some output starting with the Maven version number, such as: Apache Maven 2.0.9. The latest version of Maven is 2.2.1 by the time of writing this article, so you see there is the need to upgrade.
  3. Now you have to locate the mvn command in your file system. Type whereis mvn. The output will be the complete path of the executable: /usr/bin/mvn.
  4. This is most likely not the place where Maven is installed, but a symbolic link to the Maven executable of your system. To find out where this link refers to, type ln -sls -l /usr/bin/mvn (replace the path with your own mvn location). The output will look like this: lrwxr-xr-x 1 root wheel 37 2 Sep 22:39 /usr/bin/mvn -> /usr/local/apache-maven-2.0.9/bin/mvn
  5. Now change to the parent directory of the Maven installation. cd /usr/local
  6. Open Safari and download Maven from the Maven Homepage. Instead of downloading with Safari, you can also use a command line tool. Please use the mirror which is best for you: http://apache.linux-mirror.org/maven/binaries/apache-maven-2.2.1-bin.tar.gz
  7. Now extract the archive: tar -xzvf apache-maven-2.2.1-bin.tar.gz
  8. Optional: move the extracted archive to the right folder: sudo mv apache-maven-2.2.1 /usr/local
  9. Now link the Maven command to the new version: sudo ln -fs /usr/local/apache-maven-2.2.1/bin/mvn /usr/bin/mvn

That’s it. Now you can try if the latest version is actually installed. Type mvn -version again, and you will see:

Maven Version Output

If you are not able to execute the mvn command, it is possible that the execute flag is missing. Change this by typing chmod a+x /usr/local/apache-maven-2.2.1/bin/mvn

My Development Environment

As CloudMe will not just focus on Java development, but will also utilize GAE (Google App Engine), I had to modify my development environment to support Python. I decided to use Eclipse as I’m already familiar with it from the Java development (I tried NetBeans, which is also really good, and needs less memory, but being more familiar with Eclipse made the difference). For this project I did a clean install:

For GAE, some documentation is required (considering that I’m new to Python):