Tuesday 10 July 2012

iPhone app that uses a web service

It took me many months of naps, but I created an iPhone app that uses the web service I created in a previous blog entry.  It took me a while to learn the language since I could only devote 20 - 30 minutes at a time here and there.  However, I did it and got a simple app working!

I used the following resources:


It's been fun doing this and I'm happy I reached my goal of a creating an iPhone app that interacts with a restful web service running on ec2.  I learned a lot from all of this, but still have lots to learn!

Monday 9 July 2012

Running the Jersey web service on AWS with Elastic Beanstalk

In a previous blog entry, I created a web-service using Jersey that calculates the area of various shapes. In this entry, I deploy the web-service to AWS using Elastic Beanstalk.

Running the Jersey web service on Elastic Beanstalk was fairly straight forward.  I followed the instructions for creating a new application.  However, I did come across an issue with the health check, that required some slight tweaking.

Health Check

Beanstalk will send a health check to your application.  By default, the application health check URL is the application root (e.g., http://myapp.elasticbeanstalk.com/) and it expects a response of 200 OK for the application to be considered healthy.

With my application, the root will return a 405 response.  However, Beanstalk will let you configure the health check url.  So, I decided to implement a health check method for Beanstalk to call.  I could have setup the health check url to call one of the existing methods (i.e. call the square method), but I figured a health check method would be better.  I added the following method to the "CalculateAreaResource" class

 @Path("/healthcheck")
    @GET
    @Produces(MediaType.TEXT_HTML)
    public String healthCheck() {
        return Response.Status.OK.name();
    }
I then set the url health check in Elastic Beanstalk to "/calculate/area/healthcheck". However, my beanstalk environment failed to build with the error:
Your health check URL may be misconfigured. If your application does not respond to requests at http://calculate.elasticbeanstalk.com:80/calculate/area/healthcheck, modify the health check URL to a valid path.

Fixing the Health Check URL

I knew from running locally that http://localhost:8080/calculate/area/healthcheck worked, so I ssh'd into the ec2 instance.  Checking the tomcat log files and web-app directory, I noticed that my war was deployed as the ROOT web-app and not into the "calculate" context as I had been using locally.  (Note: the tomcat directory is in /opt/tomcat7)

I modified the url health check in the Elastic Beanstalk settings from "/calculate/area/healthcheck" to
"/area/healthcheck" and restarted the environment. It loaded properly and I could access my web service!

For details on how to ssh into your instance, please see the reference links below.

References:



Sunday 25 March 2012

Jersey, JSON and JUnit

In a previous blog entry I got a simple, HelloWorld, Jersey web service working.  Expanding on that, I created a slightly more complex web service that calculates the area of a square, rectangle or triangle.

You can download the completed project here

The slightly more complex web service incorporated the following:

  • read parameters from the path
  • return the result in JSON format
  • unit tests

@PathParam

The parameters are distinguished in the path attribute by the "{" and "}" braces. In the method signature they are referenced by the @PathParam annotation and the variable name. Example:
    
    @Path("/rectangle/{width}/{height}")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String calculateRectangle(@PathParam("width") double width, @PathParam("height") double height) {
        double result = calculator.calculateRectangle(width, height);
        return formatter.formatAsJson(result);
    }

JSON

Jersey provides 3 ways of working with JSON:
  • POJO support 
  • JAXB based JSON support 
  • Low-level, JSONObject/JSONArray based JSON support
In my case I used the Low-level method as my needs were very basic and this seemed the simplest approach.

Example:
  JSONObject format = new JSONObject();
  format.put("result", value);
  return format.toString();

You will need to include the "jersey-json" dependency in your pom.xml file to use the JSON support.

Unit Testing


Unit testing was pretty easy.  Jersey provides several test frameworks to choose from.  I used the inmemory framework. 

 <dependency>            
  <groupId>com.sun.jersey.jersey-test-framework</groupId>
  <artifactId>jersey-test-framework-inmemory</artifactId>            
  <version>1.12</version>            
  <scope>test</scope>        
 </dependency>

Accessing the Web Service

Examples of accessing the 3 area calculations:

Square 
http://localhost:8080/calculate/area/square/{side}
Example: http://localhost:8080/calculate/area/square/4
Result: {"result":16}

Rectangle
http://localhost:8080/calculate/area/rectangle/{width}/{height}
Example: http://localhost:8080/calculate/area/rectangle/4/2
Result: {"result":8}

Triangle
http://localhost:8080/calculate/area/triangle/{base}/{height}
Example: http://localhost:8080/calculate/area/triangle/4/3
Result: {"result":6}

Well that's it for now.  Next step is to figure out how to write an iPhone app to access this web service.

References

http://jersey.java.net/nonav/documentation/latest/index.html - Jersey user's guide.

Thursday 8 March 2012

Whew!

Well, that was a lot, but I finally got my "hello world" restful web service using jersey completed.  A long the way I delved into jersey, tomcat, git, github and developing on a mac.  One of the biggest hurdles was the context swapping as I usually could only work for a short time and could go a day or more without working on it.

But, I got "hello world" working.  Next stop, modifying the web service to actually do something!  I'm going to make a temperature converter.

Ignore files from Git

I've created my hello project and want to put it into Git.  All the online tutorials I read start with the same commands when creating a project:

git init
git add .

However, doing this will result in adding files and directories I do not want to commit. Fortunately, you can setup exclusions with git. There are several ways to do exclusions.  I used the method of adding a global exclusion file:

git config --global core.excludesfile ~/.global_ignore

This command sets up a global exclude file named ".global_ignore". So, any project I setup with git will use the exclusions I define in that file.

Here is what is in my .global_ignore file:

#generic files to ignore
*.DS_Store

#Java files
*.class
*.jar
*.war
*.ear

#Maven
target/

#IntelliJ
*.iml
*.idea

Now, when the "git add ." command is run, only my source files are marked for addition.

# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached ..." to unstage)
#
# new file:   README
# new file:   pom.xml
# new file:   src/main/java/foo/bar/HelloWorld.java
# new file:   src/main/webapp/WEB-INF/web.xml
# new file:   src/main/webapp/index.jsp


References:
http://man.cx/gitignore - MAN page for gitignore
https://github.com/github/gitignore - A collection of useful .gitignore templates
http://help.github.com/ignore-files/ - GitHub's help page for gitignore

How to create a web service using Jersey, Maven and Tomcat

This post will describe how to create a "HelloWorld" web service using Jersey, Tomcat and Maven.  The finished project can be downloaded from GitHub at https://github.com/Naptimecoder/hello.git.

Technologies used

The following technologies were used.
  • Tomcat (version 7.0.26 was used with this project)
  • Maven (version 3.0.3 was used with this project)
  • An IDE of your choice - I'm using IntelliJ ( community edition)
  • Jersey - but we will get it using Maven.

Create the maven project

Create a new maven web-app archetype project either through your IDE (if it supports Maven integration) or via the command line.  If you are using the command line, the command will be:

mvn archetype:generate -DgroupId=foo.bar -DartifactId=hello -DarchetypeArtifactId=maven-archetype-webapp

After creating the project you should see a directory structure like the following:



Add the Jersey dependencies

Next modify the pom.xml file to include the jersey dependencies.

Note: In the latest release of jersey the com.sun.jersey.spi.container.servlet.ServletContainer class has been moved, so the jersey-servlet dependency is now required.  If you do not include the dependency you will get a nasty "java.lang.ClassNotFoundException: com.sun.jersey.spi.container.servlet.ServletContainer" error in your tomcat log file.

The decencies section of the pom.xml file should look like this:
<dependencies>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>1.12</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-servlet</artifactId>
            <version>1.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


Create the web-service

Next create the java web-service class.  This is known as the "Root Resource Class" and is a POJO that is annotated with a @Path or has a method annotated with the @Path or a request type (i.e. @GET).

Here is the HelloWorld class I created:


package foo.bar;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/world")
public class HelloWorld {

    @GET
    @Produces(MediaType.TEXT_HTML)
    public String sayHtmlHello() {
        return "Hello!Hello, hello! ";
    }
}

The "Path" annotation indicates the URI this class will be available at relative to your base URL. For example, if this web-app is launched at localhost using a context of "hello" and no URL pattern is defined in the web.xml servlet mapping section, then the web service will be available at http://localhost:8080/hello/world.

The "GET" annotation indicates this method will respond to HTTP Get requests.

The "Produces" annotation indicates the MIME response the method will return.

Setup the web.xml file


Next, the web.xml file needs to be setup. Here is mine:

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5" >
     <servlet >
         <servlet-name >HelloWorld Jersey Service </servlet-name >
         <servlet-class >com.sun.jersey.spi.container.servlet.ServletContainer </servlet-class >
         <init-param >
             <param-name >com.sun.jersey.config.property.packages </param-name >
             <param-value >foo.bar </param-value >
         </init-param >
         <load-on-startup >1 </load-on-startup >
     </servlet >
     <servlet-mapping >
         <servlet-name >HelloWorld Jersey Service </servlet-name >
         <url-pattern >/* </url-pattern >
     </servlet-mapping >
 </web-app >

The web.xml file does the following:
  •  The init-param tells the jersey ServletContainer to look for our Root Resource Class (i.e. our HelloWorld class) in the foo.bar package. There are other ways to register this; see the jersey documentation for more details
  • Loads the ServletContainer at startup.  A value of 1 indicates the ServletContainer is a high priority servlet to load
  • The url-pattern can be used to define your URL. For example, running local host with a context of "hello" and path annotation of "world" on the HelloWorld class:


Build the project

If you use maven from the command line then use the following to build the project:

mvn package

Otherwise, use your IDE to do the maven package phase. Either way, the result should be a hello.war file created in the target directory.

Deploy to Tomcat

There are several ways to deploy the hello.war file to Tomcat. See the Tomcat Documentation for the option best for you.

For myself, I just dropped the hello.war file into the CATALINA_HOME/webapps  directory and started tomcat up.

View the web service

Point a browser to http://localhost:8080/hello/world and you should see the output of "Hello, hello!"

References

Help documents and tutorials for jersey:
http://docs.oracle.com/cd/E19776-01/820-4867/index.html
http://jersey.java.net/nonav/documentation/latest/user-guide.html
http://www.vogella.de/articles/REST/article.html

Overview of what a Restful web service is:
http://www.ibm.com/developerworks/webservices/library/ws-restful/

Technologies used:
http://jersey.java.net/
http://maven.apache.org/
http://tomcat.apache.org/

Monday 5 March 2012

Git Git Git

I want to set up version control for my little project as well.  Over the years I've used Visual Source Safe, StarTeam, and  Subversion.  For this project I'm going to use Git.

Why?

  • I haven't used Git before, and it seems to be a popular VCS choice these days.
  • I want to share my final project and GitHub provides free hosting for public projects.  
  • Xcode prompts you to setup your project in Git.  
So, Git it is!

I followed the steps on GitHub and found the to be pretty straight forward.  http://progit.org/book/ch1-3.html has a good overview of what Git is and how it works.  I didn't follow the installations steps on that site though.  I just went to the Git site and downloaded it, setup was easy.

Well, I got everything setup on GitHub next step will be to get my project setup and committed!