Deploying the android libraries into your maven repository

Maven is a fantastic build tool, and a great addition to anyone developing on the android platform, however one of the first hurdles that people often stumble upon, is when their project involves one of the SDK libraries, such as Google Maps.

You’ll most likely see something like this when you attempt to first compile the project :

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 6.597s
[INFO] Finished at: Thu Jul 19 10:28:12 BST 2012
[INFO] Final Memory: 7M/81M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project WifiSpotter: Could not resolve dependencies for project com.jameselsey.android.apps.wifispotter:WifiSpotter:apk:0.1-SNAPSHOT: Failed to collect dependencies for [com.google.android:android:jar:2.1.2 (provided), com.google.android:android-test:jar:2.2.1 (provided), com.pivotallabs:robolectric:jar:1.0 (test), junit:junit:jar:4.8.2 (test), com.google.android.maps:maps:jar:8_r1 (provided)]: Failed to read artifact descriptor for com.google.android.maps:maps:jar:8_r1: Could not transfer artifact com.google.android.maps:maps:pom:8_r1 from/to cloudbees-private-release-repository (https://repository-
[ERROR] jameselsey
[ERROR] .forge.cloudbees.com/release): IllegalArgumentException: Illegal character in authority at index 8: https://repository-
[ERROR] jameselsey
[ERROR] .forge.cloudbees.com/release/com/google/android/maps/maps/8_r1/maps-8_r1.pom

As we can see, maven is unable to find the maps artefact, and rightly so. This is because the Google jars are not available (at least not at the time of writing this) on the maven central repositories. Fortunately for us, its relatively easy to resolve this, we just need to obtain the artefacts from our android home area, and then install them to our maven repositories so our projects have access to them.

You could manually install all of them, but this would be quite a lengthy task, and relatively unnecessary with the help of the maven-android-sdk-deployer, this nifty little tool will extract the libraries from your local android SDK installation, and install them as maven dependencies, to your local repository. From there, you can just depend on them as any other maven artefact, such as :

<dependency>
  <groupId>android</groupId>
  <artifactId>android</artifactId>
  <version>4.1_r2</version>
  <scope>provided</scope>
</dependency>

There is no need for me to cover how to use this tool, since it is pretty well documented, however I would like to refer you to a previous post of mine regarding deploying maven artefacts to a CloudBees repository, combined with this post, you can quite easily and reliably maven-ise the android dependencies, and deploy them into the cloud. Then you can build your android projects using maven from anywhere, and also take advantage of the free Jenkins service they provide.

Remember to drop in the repository into the pom.xml, and then you can simply run :

mvn clean install deploy:deploy

Hope this helps, if anything is unclear, please let me know!

Recursively deleting .svn directories

Messing around with your subversion directories and fed up of the .svn hidden folders laying around? If you try and checkin some directories that contain a .svn folder from some other repository, you’re going to have a whole world of pain trying to fix it (speaking from first hand experience here)

The easiest way to clear up rogue .svn directories is to run this command (on linux or mac). It will recursively find all directories named .svn, and pass them in for removal.

rm -rf `find . -type d -name .svn`

On a Windows 7 environment, I find the easiest way is to just open Windows Explorer in the root directory that you’re interested in, and search for .svn in the top right hand search bar, then highlight all results for .svn and delete, easy :)

Hope this helps

Deploying artefacts into your CloudBees maven repositories.

If you’re like me, and have a fair few hobby projects on the go at any one time, you’re may want to take advantage of some of the free cloud services that are available out there. I’m particulary fond of the Maven repositories that CloudBees offer, as it gives you a safe and easy way to deploy your artefacts, whether they’re 3rd party libraries, snapshots, or even releases of your own software.

Head over to CloudBees.com and register an account, its free.

I’ve recently been doing a fair bit of work 3rd party libraries that are not available on the maven repositories, you have to download the source and compile it yourself (I have another post about an example of that). Since I often develop on different machines, and I’m not actually changing the library, I wanted a single place where I could upload a pre compiled copy of it and just depend on it as I would any other library, such as JUnit.

The first task, is to get your project compiling and working locally, once that is done you can then add the following into your pom.xml

Repository (that references a configured repository on ~/.m2/settings.xml)

<repository>
            <id>cloudbees-private-snapshot-repository</id>
            <name>cloudbees-private-snapshot-repository</name>
            <url>dav:https://repository-jameselsey.forge.cloudbees.com/snapshot/</url>
        </repository>

Also, since maven 3 requires the webdav extension, you’ll need to add this into the build/extensions section of your pom.xml:

<extensions>
            <!-- Extension required to deploy a snapshot or a release to the CloudBees remote maven repository using Webdav -->
            <extension>
                <groupId>org.apache.maven.wagon</groupId>
                <artifactId>wagon-webdav</artifactId>
                <version>1.0-beta-2</version>
            </extension>
        </extensions>

After that, make sure that your ~/.m2/settings.xml file contains details of your CloudBees repositories, here is my copy, make sure you put your password in, and replace occurences of “jameselsey” with your own user ID.

<?xml version="1.0"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
-->
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
    <server>
        <id>cloudbees-private-snapshot-repository</id>
        <username>jameselsey</username>
        <password>YOUR_PASSWORD_HERE</password>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
    </server>
    <server>
        <id>cloudbees-private-release-repository</id>
        <username>jameselsey</username>
        <password>YOUR_PASSWORD_HERE</password>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
    </server>
    <server>
        <id>cloudbees-private-snapshot-plugin-repository</id>
        <username>jameselsey</username>
        <password>YOUR_PASSWORD_HERE</password>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
    </server>
    <server>
        <id>cloudbees-private-release-plugin-repository</id>
        <username>jameselsey</username>
        <password>YOUR_PASSWORD_HERE</password>
        <filePermissions>664</filePermissions>
        <directoryPermissions>775</directoryPermissions>
    </server>
</servers>
<profiles>
    <profile>
        <id>cloudbees.private.release.repository</id>
        <activation>
            <property>
                <name>!cloudbees.private.release.repository.off</name>
            </property>
        </activation>
        <repositories>
            <repository>
                <id>cloudbees-private-release-repository</id>
                <url>https://repository-jameselsey.forge.cloudbees.com/release</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </repository>
        </repositories>
    </profile>
    <profile>
        <id>cloudbees.private.snapshot.repository</id>
        <activation>
            <property>
                <name>!cloudbees.private.snapshot.repository.off</name>
            </property>
        </activation>
        <repositories>
            <repository>
                <id>cloudbees-private-snapshot-repository</id>
                <url>https://repository-jameselsey.forge.cloudbees.com/snapshot</url>
                <releases>
                    <enabled>false</enabled>
                </releases>
                <snapshots>
                    <enabled>true</enabled>
                </snapshots>
            </repository>
        </repositories>
    </profile>
    <profile>
        <id>cloudbees.private.release.plugin.repository</id>
        <activation>
            <property>
                <name>!cloudbees.private.release.plugin.repository.off</name>
            </property>
        </activation>
        <pluginRepositories>
            <pluginRepository>
                <id>cloudbees-private-release-plugin-repository</id>
                <url>https://repository-jameselsey.forge.cloudbees.com/release</url>
                <releases>
                    <enabled>true</enabled>
                </releases>
                <snapshots>
                    <enabled>false</enabled>
                </snapshots>
            </pluginRepository>
        </pluginRepositories>
    </profile>
    <profile>
        <id>cloudbees.private.snapshot.plugin.repository</id>
        <activation>
            <property>
                <name>!cloudbees.private.snapshot.plugin.repository.off</name>
            </property>
        </activation>
        <pluginRepositories>
            <pluginRepository>
                <id>cloudbees-private-snapshot-plugin-repository</id>
                <url>https://repository-jameselsey.forge.cloudbees.com/snapshot</url>
                <releases>
                    <enabled>false</enabled>
                </releases>
                <snapshots>
                    <enabled>true</enabled>
                </snapshots>
            </pluginRepository>
        </pluginRepositories>
    </profile>
</profiles>
</settings>

Now, if you run mvn clean install deploy:deploy, maven will create a clean build of your application, install it to your local repository, and then deploy it to your CloudBees snapshot repo.

[INFO] --- maven-deploy-plugin:2.7:deploy (default-cli) @ tess-two ---
WAGON_VERSION: 1.0-beta-2
Downloading: dav:https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/maven-metadata.xml
Downloaded: dav:https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/maven-metadata.xml (769 B at 0.7 KB/sec)
Uploading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/tess-two-0.0.1-20120720.120205-2.apklib
Uploaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/tess-two-0.0.1-20120720.120205-2.apklib (5865 KB at 449.0 KB/sec)
Uploading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/tess-two-0.0.1-20120720.120205-2.pom
Uploaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/tess-two-0.0.1-20120720.120205-2.pom (3 KB at 1.2 KB/sec)
Downloading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/maven-metadata.xml
Downloaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/maven-metadata.xml (276 B at 0.6 KB/sec)
Uploading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/maven-metadata.xml
Uploaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/0.0.1-SNAPSHOT/maven-metadata.xml (769 B at 0.4 KB/sec)
Uploading: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/maven-metadata.xml
Uploaded: https://repository-jameselsey.forge.cloudbees.com/snapshot/tess-two/tess-two/maven-metadata.xml (276 B at 0.2 KB/sec)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 49.874s
[INFO] Finished at: Fri Jul 20 13:02:24 BST 2012
[INFO] Final Memory: 16M/81M
[INFO] ------------------------------------------------------------------------

The same should work for releases, just alter the repository in the pom to point to the releases repo. This isn’t particularly CloudBees specific either, it should work on any remote maven repository, I just like CloudBees, and no, I don’t work for them :P

Any comments/suggestions, please shout!

Tesseract OCR on Android is easier if you Maven-ise it, works on Windows too…

I’ve spent the past few months working on an android application that involves an element of OCR capability, its been quite a painful journey so this is my attempt to reflect on these experiences and hopefully help others who follow in my path.

From Wikipedia : In geometry, the tesseract, also called an 8-cell or regular octachoron or cubic prism, is the four-dimensional analog of the cube.

First off, lets just cover the basics. OCR stands for Optical Character Recognition, which is the process of taking an image, and being able to interpret the image and obtain textual data from it. For example, you take a photograph of a road sign, this would be an image file such as a JPEG. You can clearly see that the road sign says “Slow down”, however to a computer program, its just an image file. OCR enables the program to literally scan the image and find text, which your program can then use elsewhere in its workings.

After spending the best part of several days attempting to create a simple OCR application on android, and after suffering much frustration due to the lack of general resources available on the subject, I was able to find some good material by Gautam and rmthetis.

Whilst those guys have made a fantastic effort in their tutorials, I still needed to do further tasks to get an OCR demo off the ground, so hopefully this post will be a good supplement to their work.

The first misconception I wanted to clean up on is “this will only work on linux“, whilst the tutorials from the aforementioned authors are targetted against linux development environments, the above statement is not entirely true. Following their tutorials I was able to get it working first time on my Windows 7 development laptop. I also got this working on my new replacement Windows 7 laptop a week or two later without any troubles (and mc Macbook Pro too), all I did was follow these instructions which are on the github page for tess-two:

git clone git://github.com/rmtheis/tess-two tess
cd tess/tess-two
ndk-build
android update project --path . 
ant release

The above will clone the tess-two project by rmtheis, build the shared objects, update the project, then build the APK. I didn’t have any trouble doing this on a Windows environment. It is worth noting however, that the ndk-build can take time, I think on my first laptop it took around 20-30 minutes to complete, but it was a low spec machine.

Maven is Awesome with a Capital A

Most of the pain I experienced was integrating the libraries into my existing project. My project was already using maven so it made sense to attempt to package up the tess projects as libraries and depend on them as I would any other library, such as commons-lang (I’ve recently discovered that Google Guava is far better, but thats another topic).

I had quite a lot of trouble doing this at first, but it probably wasn’t aided by the fact I was moving my development environment from Windows 7 to Mac OS X Lion, attempting to (for the 3rd time) migrate from IntelliJ Idea to Eclipse (I gave up, Idea is still far superior and easier to use IMHO) and I was trying to ensure the IDE was happy with the project structure, which is no mean feat. I had a lot of problems trying to get m2eclipse to recognise the APKLIB packaging concept, even with the m2eclipse android connector I still struggled with plugin compatibility issues and general mis-understanding between the eclipse plugins and maven. It always compiled directly from the command line however.

Eventually, all it boiled down to, was including a pom.xml in both the tess-two and eyes-two root folders, which instructs maven to package them up as apklib files. As detailed on the android-maven-plugin website, the plugin is smart enough to know that when you request an apklib type project, it knows exactly where to find all the artefacts to include.

After following the above instructions that I’ve pulled from the tess-two github page, drop in this pom.xml into the root folder, tess/tess-two :

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>tess-two</groupId>
  <artifactId>tess-two</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>apklib</packaging>
  <dependencies>
        <dependency>
            <groupId>com.google.android</groupId>
            <artifactId>android</artifactId>
            <scope>provided</scope>
            <version>2.3.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
            <version>4.8.2</version>
        </dependency>
    </dependencies>

    <build> 
        <sourceDirectory>src</sourceDirectory>
        
        <plugins>
            <plugin>
                <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                <artifactId>android-maven-plugin</artifactId>
                <extensions>true</extensions>
                <version>3.2.0</version>
                <configuration>
                    <sdk>
                        <platform>10</platform>
                    </sdk>
                    <undeployBeforeDeploy>true</undeployBeforeDeploy>
                    <attachSources>true</attachSources>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Drop into the command line, and run :

mvn clean install

This will then package up the tess-two application into an APKLIB file, and install it to your local maven repository. You can then depend on tess-two for any project you like, using the following dependency :

        <dependency>
            <groupId>tess-two</groupId>
            <artifactId>tess-two</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <type>apklib</type>
        </dependency>

Of course, feel free to change the group ID or version numbers as you see fit, just make sure they match up to the tess-two pom. You can also use the above approach for the eyes-two project, but remember that eyes-two is dependent on tess-two, so don’t forget the dependency!

You should then be able to start using the TessBaseAPI as Gautam covers in his post, this post here merely gets you going with maven. I’ve been in contact with Robert, chances are we’ll be getting this properly mavenised soon, so you can then depend on it from the central repositories rather than doing the installation mentioned here, we’ll keep you posted. (Robert, if you’re reading, get back to me mate!)

Hope this is of help, any questions then please ask, I’ll also be covering the iOS tesseract soon too, that was a little easier to get started.

Thanks

Automating android application signing and zipaligning with maven

Code rage

This is something that has had me tearing my hair out for a few days now, I was pretty much border-line braveheart-ing my screen….

Code rage

I’ve recently been on a little drive to try to maven-ize my projects. All had been going well until I needed to sign and zipalign my APKs. This post will help you conquer that barrier with the use of some maven plugins.

When using ant, I was able to simply enter keystore details into build.properties and just call “ant release”. Unfortunately that approach doesn’t carry across to maven, and you have to provide some more configuration.

Firstly, before we go any further, I’m going to assume that you already have a maven android project setup, so you have a pom.xml, you’ve configured the maven-android-plugin and you can run “mvn clean install” to build your APK, and “mvn android:deploy” to deploy it to an emulator. If you haven’t got that far, I’d suggest you have a look at one of my previous posts to help get you up to speed.

So, when you want to build your application with maven, you’d run “mvn install”. That will, by default, use a debug key to sign your APK. When we want to build a releasable APK we still want to execute the same install goal, however we’ll want to use a proper key. Luckily, maven provides something called profiles.

In short, maven profiles allow you to still perform the same standard goals, yet they behave slightly different, in the manner of binding extra steps to them, all will come clearer in a moment.

This has already been covered, in a useful post by the guys at Novoda, and various other blog posts scattered around the web. I’ve followed at least 10 tutorials and each time I was unable to get the signing process to work correctly, each time I encountered the following error :

INFO] jarsigner: attempt to rename C:\android-projects\jameselsey_andsam_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar to C:\android-projects\jameselsey_ands
am_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar.orig failed
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Failed executing 'cmd.exe /X /C "C:\development\tools\Java\jdk1.6.0_20\jre\..\bin\jarsigner.exe -verbose -keystore my-release-key.keystore -storepass '*****' -keypass '
*****' C:\android-projects\jameselsey_andsam_branch_mavenbranch\target\LanguageSelection-1.0.0-SNAPSHOT.jar mykeystore"' - exitcode 1
[INFO] ------------------------------------------------------------------------

I’d tried everything, even copying out the command and pasting into a command window worked, but I could not get it to work from maven. Unfortunately it seems there may be an issue with the maven-jarsigner-plugin (as suggested in the comments on the Novoda post). However fear not, for there is an alternative, the maven-jar-plugin.

The maven-jar-plugin is a similar plugin to the jarsigner plugin, however the signing APIs are now deprecated and it points you to use the (apparently) broken maven-jarsigner-plugin. Using a deprecated API doesn’t particulary concern me in this instance, as its just signing artefacts.

Take a look at my profiles section, copy this into your pom.xml :

<profiles>
<profile><!-- release profile. uses keystore defined in keystore.* properties. signs and zipaligns the app to the target folder-->
            <id>release</id>
            <activation>
                <activeByDefault>false</activeByDefault>
            </activation>
            <build>
                <defaultGoal>install</defaultGoal>
                <finalName>${project.artifactId}-${project.version}</finalName>
                <plugins>
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-jar-plugin</artifactId>
                        <version>2.2</version>
                        <executions>
                            <execution>
                                <id>signing</id>
                                <goals>
                                    <goal>sign</goal>
                                </goals>
                                <phase>package</phase>
                                <inherited>true</inherited>

                                <configuration>
                                    <keystore>
                                        my-release-key.keystore
                                    </keystore>
                                    <storepass>mypassword</storepass>
                                    <keypass>mypassword</keypass>
                                    <alias>mykeystore</alias>
                                    <verbose>true</verbose>
                                    <verify>true</verify>
                                </configuration>
                            </execution>
                        </executions>
                    </plugin>

                    <plugin>
                        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                        <artifactId>maven-android-plugin</artifactId>
                        <inherited>true</inherited>
                        <configuration>
                            <sign>
                                <debug>false</debug>
                            </sign>
                        </configuration>
                    </plugin>

                    <plugin>
                        <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                        <artifactId>maven-android-plugin</artifactId>
                        <configuration>
                            <zipalign>
                                <verbose>true</verbose>
                                <skip>false</skip>
                                <!-- defaults to true -->
                                <inputApk>${project.build.directory}/${project.artifactId}-${project.version}.apk</inputApk>
                                <outputApk>${project.build.directory}/${project.artifactId}-${project.version}-RELEASE.apk
                                </outputApk>
                            </zipalign>

                        </configuration>
                        <executions>
                            <execution>
                                <id>zipalign</id>
                                <phase>install</phase>
                                <goals>
                                    <goal>zipalign</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
</profiles>

OK, so lets walk through what the above profile does. Firstly, the “id” of the profile is “release”, so when you want to apply this profile, you’d run “mvn install -Prelease”. The “activeByDefault” is set to false, which means you need to use the above arguement, if you flip that over, you won’t need the P flag.

The execution goal is to “sign”, which is the API on the plugin, documented here. We bind this execution on to the standard “package” goal. Then we provide the configuration elements which specify the details of the keystore.

In pure English, this binds the plugin phase onto the package goal of maven, so anytime we run using this profile it’ll execute the jar signing of our artefacts. The “verify” tag gives us extra piece of mind by verifying that the signing was successful afterwards.

I’ve also setup a zipalign profile that will take the APK, zipalign it, and rename it to “*-RELEASE.apk”, so I know that particular APK is the one which I’ll release to market.

So thats it, once more a success, and its just one small step on the ladder to android glory!

Phhew!! Done, finally I was able to shutdown the laptop and go to sleep at 3am….on a school night!!!

Good luck, feel free to comment!

Peace.

Getting started with Git, and GitHub, the noobs guide

I’ve always been a Subversion man myself, but today I took Vaders’ advice and joined the darkside. As part of a tutorial I wrote on here I wanted to host some code on Github for people to download, so I had to learn some basic Git usage, heres how to get started.

First thing, head over to Github and get yourself an account, it only takes about 5 minutes. After that, create a repository. You can have as many public repositories as you want using a free account, so don’t worry about wasting any of your allowance. Think of a repository as a project, for each of my android applications that I have hosted I have them in their own repository, you could easily have them all in one, but its a lot neater to keep them separate, and gives you the choice to have a wiki or issue tracking page separate across the repositories.

After you’re all setup on Github, go ahead and download the client here, then we’ll need to setup a few things on your development environment.

Setting up a Git SSH key

You’ll need to setup an SSH key in order to commit anything to Github, open up Git Bash. You can find this under Start > Programs > Git > Git Bash.

Once you’ve got the Git Bash console open, run the following to generate a key:

James@NEVADA ~/.ssh
$ ssh-keygen -t rsa -C "james.elsey@gmail.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/James/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/James/.ssh/id_rsa.
Your public key has been saved in /c/Users/James/.ssh/id_rsa.pub.
The key fingerprint is:
85:70:7f:d1:3d:94:c1:89:9f:36:b4:9d:04:81:ec:bd james.elsey@gmail.com

This will generate a key into the file id_rsa.pub, so if you run the following you can see what that key is :

cat id_rsa.pub

Copy the key value, then go back to Github, click on Account settings and then add a public key, using that value in the big box.

After thats done, we’re ready to start checking your code into your Github repository.

Create a project, then check it into Github

I’m going to assume you’ve already created a dummy application on your environment that you want to commit to Github. This can be Android, J2EE or anything you want, but for the purposes of this demo I’ve created an android application.

Open up a command prompt and cd into the root directory of your project. Then run the following :

# Initialize the local Git repository
git init
# Add all (files and directory) to the Git repository
git add .
# Make a commit of your file to the local repository
git commit -m "First check-in."
# Show the log file
git log

What this does is add and commit your files under the current directory (so thats your entire project) into a local Git repository on your local disk. Thats great, but if your PC fails you’ll lose your work, so we need to get that pushed up onto Github, use the following to do so:

C:\development\projects\TextToSpeechDemo>git push -u origin master
Enter passphrase for key '/c/Users/James/.ssh/id_rsa':
Counting objects: 47, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (30/30), done.
Writing objects: 100% (47/47), 20.41 KiB, done.
Total 47 (delta 3), reused 0 (delta 0)
To git@github.com:jameselsey/TextToSpeechDemo.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

What this does is push all from origin into master, master is a bit like trunk in subversion terms.

So thats it, in 10 minutes you’ve been able to setup a Github account, setup an SSH key, create a repository, commit and push your code into your Github repository.

You can also create a few branches, commit into those and push out into their own branches on Github, like I have done here :

C:\development\projects\TextToSpeechDemo>git branch
* master

C:\development\projects\TextToSpeechDemo>git branch-a
git: 'branch-a' is not a git command. See 'git --help'.

C:\development\projects\TextToSpeechDemo>git branch -a
* master
  remotes/origin/master

C:\development\projects\TextToSpeechDemo>git branch TextToSpeechDemoStaticSpeech

C:\development\projects\TextToSpeechDemo>git checkout TextToSpeechDemoStaticSpeech
M       .idea/workspace.xml
Switched to branch 'TextToSpeechDemoStaticSpeech'

C:\development\projects\TextToSpeechDemo>dir
 Volume in drive C has no label.
 Volume Serial Number is 5EF1-749D

 Directory of C:\development\projects\TextToSpeechDemo

26/02/2011  13:28    <DIR>          .
26/02/2011  13:28    <DIR>          ..
26/02/2011  13:43    <DIR>          .idea
26/02/2011  13:28               691 AndroidManifest.xml
26/02/2011  12:21    <DIR>          assets
26/02/2011  12:21    <DIR>          bin
26/02/2011  12:21               696 build.properties
26/02/2011  12:21             3,294 build.xml
26/02/2011  12:21               362 default.properties
26/02/2011  12:21    <DIR>          gen
26/02/2011  12:21    <DIR>          libs
26/02/2011  12:21               447 local.properties
26/02/2011  13:28    <DIR>          out
26/02/2011  12:21             1,195 proguard.cfg
26/02/2011  12:21    <DIR>          res
26/02/2011  12:21    <DIR>          src
26/02/2011  12:21             1,952 TextToSpeechDemo.iml
               7 File(s)          8,637 bytes
              10 Dir(s)  33,205,288,960 bytes free

C:\development\projects\TextToSpeechDemo>git commit -a -m "Moved static speech demo into separate branch to keep it"
[TextToSpeechDemoStaticSpeech 46098c9] Moved static speech demo into separate branch to keep it
 1 files changed, 2 insertions(+), 2 deletions(-)

C:\development\projects\TextToSpeechDemo>git push -u origin TextToSpeechDemoStaticSpeech
Enter passphrase for key '/c/Users/James/.ssh/id_rsa':
Counting objects: 7, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 456 bytes, done.
Total 4 (delta 3), reused 0 (delta 0)
To git@github.com:jameselsey/TextToSpeechDemo.git
 * [new branch]      TextToSpeechDemoStaticSpeech -> TextToSpeechDemoStaticSpeech
Branch TextToSpeechDemoStaticSpeech set up to track remote branch TextToSpeechDemoStaticSpeech from origin.

C:\development\projects\TextToSpeechDemo>git checkout master
Switched to branch 'master'

C:\development\projects\TextToSpeechDemo>git branch TextToSpeechDemoDynamicSpeech

C:\development\projects\TextToSpeechDemo>git branch -a
  TextToSpeechDemoDynamicSpeech
  TextToSpeechDemoStaticSpeech
* master
  remotes/origin/TextToSpeechDemoStaticSpeech
  remotes/origin/master

C:\development\projects\TextToSpeechDemo>git checkout TextToSpeechDemoDynmaicSpeech
error: pathspec 'TextToSpeechDemoDynmaicSpeech' did not match any file(s) known to git.

C:\development\projects\TextToSpeechDemo>git checkout TextToSpeechDemoDynamicSpeech
M       .idea/workspace.xml
M       gen/com/jameselsey/demo/texttospeechdemo/R.java
M       res/layout/main.xml
M       res/values/strings.xml
M       src/com/jameselsey/demo/texttospeechdemo/Main.java
Switched to branch 'TextToSpeechDemoDynamicSpeech'

C:\development\projects\TextToSpeechDemo>git commit -a -m "Added a text box for dynamic speech"
[TextToSpeechDemoDynamicSpeech 0f9ef63] Added a text box for dynamic speech
 5 files changed, 116 insertions(+), 37 deletions(-)

C:\development\projects\TextToSpeechDemo>git push -u origin TextToSpeechDemoDynamicSpeech
Enter passphrase for key '/c/Users/James/.ssh/id_rsa':
Counting objects: 38, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (21/21), 2.40 KiB, done.
Total 21 (delta 7), reused 0 (delta 0)
To git@github.com:jameselsey/TextToSpeechDemo.git
 * [new branch]      TextToSpeechDemoDynamicSpeech -> TextToSpeechDemoDynamicSpeech
Branch TextToSpeechDemoDynamicSpeech set up to track remote branch TextToSpeechDemoDynamicSpeech from origin.

C:\development\projects\TextToSpeechDemo>git checkout master
Switched to branch 'master'

Hope this helps!

Further Reading

Android; Continuous integration, all made lovely with Maven

Lets face it, the eclipse ADT plugin is great for getting an android application up and running quickly, but if you want an easier way to get libraries, and a continuous intergration environment for robust automated testing and building, then maven is the way to go.

IntelliJ have recently released the Early Access Program to their version X of IDEA, this comes with Android support in the community edition, meaning we’re no longer bound to using eclipse for Android development!

The first thing you want to do, is to run through the “create new project” wizard in IntelliJ, its fairly straightforward, just run through and setup a simple android applicaiton. When you’ve got that, run it up on the emulator just to make sure any autogenerated code IntelliJ created works OK.

OK so now we’re ready to start gutting it out and providing the Maven framework. First thing you need to do, in the root directory of the android project, create a file called pom.xml with the following contents

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>MavenMess</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>apk</packaging>
    <name>Maven Android Plugin - samples</name>

    <dependencies>
        <dependency>
            <groupId>com.google.android</groupId>
            <artifactId>android</artifactId>
            <version>2.2.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <sourceDirectory>src</sourceDirectory>
        <plugins>
            <plugin>
                <groupId>com.jayway.maven.plugins.android.generation2</groupId>
                <artifactId>maven-android-plugin</artifactId>
                <version>2.6.0</version>
                <configuration>
                    <sdk>
                        <!--  platform or api level (api level 4 = platform 1.6)-->
                        <platform>8</platform>
                    </sdk>
                    <emulator>
                        <!--  the name of the avd device to use for starting the emulator-->
                        <avd>GoogleAPIs</avd>
                    </emulator>
                    <deleteConflictingFiles>true</deleteConflictingFiles>
                    <undeployBeforeDeploy>true</undeployBeforeDeploy>
                </configuration>
                <extensions>true</extensions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <!--  version 2.3 defaults to java 1.5, so no further configuration needed-->
                <version>2.3</version>
            </plugin>
        </plugins>
    </build>
</project>

The POM file is what maven uses to build/test your project. If you’re not familiar with maven at this stage I’d suggest a quick browse of their documentation to get to grips with the fundamentals.

The above POM does a couple of tasks, firstly it tells maven to build an APK file using the packaging statement. You need this otherwise maven wouldn’t know what to create, and might create a WAR or EAR file instead.

You declare the android SDK as a provided dependancy. Next comes the build section, this is where the magic happens. The source directory tells maven where it can find all your android source files to compile.

You’ll need to declare usage of the Jayway plugin, this is a neat little plugin that I picked up from Hugo Josefson from Jayway, at DroidCon UK 2010. There is some configuration that you can set here such as the API level and which emulator to deploy the application to. The second plugin is the maven Java compiler, we need this in order to actually compile the class files.

Right so thats your POM sorted, next you can go ahead and delete the following items

  • \bin
  • \libs
  • build.properties
  • build.xml

You won’t need those files/directories, those are used for the autogenerated ant build script that the android IntelliJ plugin creates, and we’re now using maven.

Right thats it for the maven configuration, next comes actually running the application. The maven goal of “mvn install” will compile all your classes, so run that to check the above is OK.

To deploy your application to a device, you can run the maven goal of “mvn android:deploy”. These goals are great, but what about a 1 button click for building and deploying? Easy…

Along the top of IntelliJ, click on the drop down menu for run targets and create a new run/debug configuration. Using the goal of “android:deploy” will deploy the application to the emulator, but you can also setup a goal of “mvn install” which happens before deployment, as shown in the screenshot below. This will build and deploy your application to the emulator with one click.

All you need to do then is to go into your emulator and start your application, simple!

Any questions/suggestions, please let me know!

Big thanks to the guys at Jayway for sharing this, and making it possible.

Modify your Java web application to run on Google App Engine

So, you have a Java web application that you would like to host somewhere for free, no worries, Google to the rescue. What is Google App Engine? Well to quote from their site…

Google App Engine lets you run your web applications on Google’s infrastructure. App Engine applications are easy to build, easy to maintain, and easy to scale as your traffic and data storage needs grow. With App Engine, there are no servers to maintain: You just upload your application, and it’s ready to serve your users.

You can serve your app from your own domain name (such as http://www.example.com/) using Google Apps. Or, you can serve your app using a free name on the appspot.com domain. You can share your application with the world, or limit access to members of your organization.

Google App Engine supports apps written in several programming languages. With App Engine’s Java runtime environment, you can build your app using standard Java technologies, including the JVM, Java servlets, and the Java programming language—or any other language using a JVM-based interpreter or compiler, such as JavaScript or Ruby. App Engine also features a dedicated Python runtime environment, which includes a fast Python interpreter and the Python standard library. The Java and Python runtime environments are built to ensure that your application runs quickly, securely, and without interference from other apps on the system.

As an overview, you will need to do the following:

  1. Read the GAE Documentation
  2. Download the GAE SDK
  3. Alter your application
  4. Test this locally using the GAE development server (as included with GAE SDK)
  5. If it all works, upload it using the AppCfg command line utility

The GAE SDK

Go ahead and download the GAE SDK, unzip this somewhere on your local hard drive, in my case this was /home/james/Development/utils/appengine-java-sdk-1.2.6

Altering your application

Next, you need to add the app engine libraries to your application, I’m using maven2 purely for ease of use, so I added this to my pom.xml file

        <dependency>
           <groupId>com.google.appengine</groupId>
           <artifactId>appengine-java-sdk</artifactId>
           <version>1.2.6</version>
       </dependency>

When you try to build the application, maven won’t be able to automatically download the jar file, so you’ll have to install that manually using the following command

mvn install:install-file -DgroupId=com.google.appengine -DartifactId=appengine-java-sdk -Dversion=1.2.6 -Dpackaging=jar -Dfile=lib/user/appengine-api-1.0-sdk-1.2.6.jar

You’ll notice that the actual jar file you need is under lib/user/ from the SDK you just downloaded.

You will need to create the appengine-web.xml file, this should reside in the same place as your standard web.xml file, under WEB-INF. The purpose of this file is to inform the GAE which application this belongs to, so you will need to add your GAE application ID into the example below, in my case it was sales-tracker

<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
   <application>sales-tracker</application>
   <version>1</version>
</appengine-web-app>

Provide an empty implementation of MultipartWrapper

The next thing that you need to do is to edit your web.xml to include the MultipartWrapperFactory, add the following into the init-param section

<init-param>
          <param-name>MultipartWrapperFactory.Class</param-name>
          <param-value>com.jameselsey.salestracker.util.EmptyMultipartWrapper</param-value>
      </init-param>

The next thing we need to do is to provide an implementation of the MultipartWrapper, it doesn’t matter where in your package structure you take care of this, providing it matches up to the declaration in your web.xml, as shown above

package com.jameselsey.salestracker.util;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import net.sourceforge.stripes.config.Configuration;
import net.sourceforge.stripes.controller.FileUploadLimitExceededException;
import net.sourceforge.stripes.controller.multipart.MultipartWrapper;
import net.sourceforge.stripes.config.ConfigurableComponent;
import net.sourceforge.stripes.controller.multipart.MultipartWrapperFactory;

/**
* GAE has no support for uploading of files, so we use this to disable that part of Stripes
*
* @author james.elsey
*/
public class EmptyMultipartWrapper implements ConfigurableComponent, MultipartWrapperFactory {

  /**
   * @see net.sourceforge.stripes.config.ConfigurableComponent#init(net.sourceforge.stripes.config.Configuration)
   */
  public void init(Configuration conf) throws Exception {
  }

  /**
   * @see net.sourceforge.stripes.controller.multipart.MultipartWrapperFactory#wrap(javax.servlet.http.HttpServletRequest)
   */
  public MultipartWrapper wrap(HttpServletRequest request) throws IOException, FileUploadLimitExceededException {
      return null;
  }
}

Upload your project to GAE

Your application should be ready to go now, build your application using

mvn clean package

Then upload it to GAE using, you have to update the war folder not the actual war file


./AppCfg.sh update ~/Development/projectname/target/myprojectname

Thats pretty much it! Good luck!

Setting up a basic Stripes framework

After being introduced to Struts1, Struts2 and SpringMVC at a very early stage in my development career, I was very happy to work on a project with Stripes. Stripes can do nearly everything I was doing with other action based frameworks, but is much simpler to use but is also a very versatile framework.

I’ve decided to put together this tutorial on how to setup a basic Stripes project with one page and one action, this will give you an idea of how the framework fits together, you can then expand on it as you wish.

Stripes is a very easy to use J2EE framework, similar to Struts but without all the heavy configuration XML files. Lets have a look at how easy it is to setup

Firstly, grab hold of an IDE such as Netbeans. Install the standalone Maven, or use the embedded version that comes with Netbeans (or just grab the plugin). I won’t go into how to set this up right now, so you’ll have to figure that out yourself.

Once that’s setup, in Netbeans go File > New Project, choose a Maven Web project. This should give you a basic skeleton of a project.

So far, your new application has no idea about stripes, so we can go ahead and fix that, this is where we benefit from using Maven.

Open up the pom.xml that is located under Project Files, and add the following into the dependencies section. What this does is to imply that our project is going to make use of the stripes, jstl and taglibs libraries. Maven will detect this and upon saving will add those libraries to our project.

<dependency>
  <groupid>net.sourceforge.stripes</groupid>
  <artifactid>stripes</artifactid>
  <version>1.5.1</version>
</dependency>
<dependency>
  <groupid>jstl</groupid>
  <artifactid>jstl</artifactid>
  <version>1.1.2</version>
</dependency>
<dependency>
  <groupid>taglibs</groupid>
  <artifactid>standard</artifactid>
  <version>1.1.2</version>
</dependency>

The only XML configuration you’ll need to worry about (apart from pom.xml, but that doesn’t count) is the standard web.xml file that’ll be present in any Java web application, go ahead and add the following into your web.xml file, it’ll be located under WEB-INF

<?xml version="1.0" encoding="UTF-8"?>
  <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>MyProject</display-name>
    <filter>
      <filter-name>StripesFilter</filter-name>
      <filter-class>net.sourceforge.stripes.controller.StripesFilter</filter-class>
      <init-param>
        <param-name>ActionResolver.Packages</param-name>
        <param-value>com.jameselsey.myproject.action</param-value>
      </init-param>
    </filter>
    <servlet>
      <servlet-name>DispatcherServlet</servlet-name>
      <servlet-class>net.sourceforge.stripes.controller.DispatcherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
    </servlet>
    <filter-mapping>
      <filter-name>StripesFilter</filter-name>
      <servlet-name>DispatcherServlet</servlet-name>
      <dispatcher>REQUEST</dispatcher>
      <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    <servlet-mapping>
      <servlet-name>DispatcherServlet</servlet-name>
      <url-pattern>*.action</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
      <welcome-file>/WEB-INF/jsp/hello.jsp</welcome-file>
    </welcome-file-list>
  </web-app>

Firstly, we declare a StripesFilter and specify which class it is from, this is part of the standard stripes setup so we can ignore that, however pay special attention to the ActionResolver parameter, that needs to match the “root” of our actions package, but we’ll come into that later.

Next we’ll need a DispatcherServlet declaration, and then we need to map stripes to intercept all requests via the DispatcherServlet. We also need to inform the servlet to filter all requests for .action. Lastly, we can specify a default page to be loaded when the application starts.

So now we have the stripes library available to us, so lets create an action and jump right in.

Create a new java class, such as com.jameselsey.action.MyHelloAction. Notice how I’ve put the action under the “action” package, the reason for this is so I can specify that package as the “root” action package in the web.xml file (check the web.xml code I posted above, the MyHelloAction will be available because it is within the package set in the ActionResolver)

Add the following into your action, you can rename variables if you like


import java.util.Date;
import java.util.Random;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;

public class MyHelloAction implements ActionBean 
{

	private ActionBeanContext ctx;

    	public ActionBeanContext getContext() 
	{        
		return ctx;    
	}

    	public void setContext(ActionBeanContext ctx) 
	{        
		this.ctx = ctx;    
	}    

	private Date date;

	public Date getDate() 
	{        
		return date;    
	}

    	@DefaultHandler    
	public Resolution currentDate() 
	{        
		date = new Date();        
		return new ForwardResolution(VIEW);    
	}

    	public Resolution randomDate() 
	{        
		long max = System.currentTimeMillis();        
		long random = new Random().nextLong() % max;        
		date = new Date(random);        
		return new ForwardResolution(VIEW);    
	}    
	
	private static final String VIEW = "/WEB-INF/jsp/hello.jsp";

}

This action will generate a date, and a random date. Notice that the currentDate method is the default handler, that means that if we come into this action and don’t specify what event we want, the currentDate will be called. This would generate a date, and then return a forward resolution. You can see at the bottom of the action we have setup a String which contains the resolution to return, in this case a JSP

Right, so now we have our action which has generated some data for us, now lets setup a JSP to display this to a user. Create a jsp called hello.jsp under WEB-INF/jsp, add the following

<%@page contentType="text/html;charset=ISO-8859-1" language="java" %>
<%@taglib prefix="s" uri="http://stripes.sourceforge.net/stripes.tld" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
      <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"    "http://www.w3.org/TR/html4/strict.dtd" >
        <html>
          <head>
            <title>Hello!</title>
          </head>
          <body>
            <h3>Hello James Elseys' Stripes Tutorial!</h3>
            <p>
              <b>
                <fmt:formatDate type="both" dateStyle="full"                                value="${actionBean.date}" />
              </b>
            </p>
            <p>
              <s:link beanclass="com.jameselsey.myproject.action.MyHelloAction"                    event="currentDate" >Show the current date and time</s:link>
              <s:link beanclass="com.jameselsey.myproject.action.MyHelloAction"                    event="randomDate" >Show a random date and time</s:link>
            </p>
          </body>
        </html>

Firstly, our JSP displays a date. As we have set a @DefaultHandler on our action, the currentDate gets served up in the JSP.

Underneath we have 2 links that go to our action class, these aren’t regular anchor links, we are making use of the stripes tags here. This allows us to bind a link to an action class, and to also specify an event. The event should match up to a method in the action class.

You should have a file structure as follows, double check that your files are in the correct place

Once your all set, try and run the application! You should get something as in my following screenshot. Its now up to you to add more actions, pages, and other features such as Data Access Objects

Thanks for reading this post, apoligies for keeping it brief but I just wanted to note down how to setup the framework while its still fresh on my mind! I’ll try to keep more posted in the future as I’m starting my own google-code hosted project using stripes. If you’ve got anything to add, or need some help, please feel free to let me know!