RSS Feed!

Recent Posts

Recent Comments

Posts Tagged ‘REST’

Urban Airship – Push Notifications

Sunday, October 4th, 2009

Today I have finally added Push Notifications to Parcel Trackr.

I decided not to waste time and I went for Urban Airship. I registered, uploaded my push certificate, downloaded the sample and integrated the two systems.

Not everything went smoothly though because when I first ran the application I got a

Failed to register with error: Error Domain=NSCocoaErrorDomain Code=3000 UserInfo=0×120610 “no valid ‘aps-environment’ entitlement string found for application”

I thought my provisioning profile did not include the right entitlement… so I re-downloaded it and tried again. Turns out I was using the wrong provisioning profile.

So if you want to avoid my mistake just make sure that after you’ve configured push services in the iPhone Dev Center you download the updated provisioning profile and then you install it via XCode.

Other things worth checking include: the product name in your build configuration matches the app id and of course, the ultimate solution, clean all targets before building!

Cheers…

Jersey 1.0.2 JSON and JAXB

Friday, May 29th, 2009

In a previous post I explained how to unit test JAX-RS. Let’s now have a look at a more complex example: implementing RESTful webservices using Jersey 1.0.2.

To get RESTful web services (JAX-RS) that produce JSON output using Jersey you have to get the following libraries:
1. Jersey 1.0.2 (see the dependencies here for a web application. Make sure you get: jersey-server.jarjersey-core.jarjsr311-api.jarasm.jar)
2. JAXB 2.1 (jaxb-impl.jarjaxb-api.jar) If you run into problems later just check that you are running jaxb 2.1.10. The 2.1.10 jaxb-impl.jar provides support for the natural jsonconfiguration.
3. JSON-lib 2.2.3 (json-lib-2.2.3-jdk15.jar) You will use this later to construct a MessageBodyWriter Provider that outputs JSON content…
Let’s start setting up the whole lot.
WEB.XML
In your web application’s web.xml make sure you’ve hooked up Jersey:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<servlet>
  <servlet-name>My Jersey Web Application</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>com.sun.jersey.config.property.resourceConfigClass</param-name>
    <param-value>com.sun.jersey.api.core.PackagesResourceConfig</param-value>
  </init-param>
  <init-param>
    <param-name>com.sun.jersey.config.property.packages</param-name>
    <param-value>net.tmro.demo.json;your.packages;separated.by.semicolons</param-value>
  </init-param>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>My Jersey Web Application</servlet-name>
  <url-pattern>/webappjson/*</url-pattern>
</servlet-mapping>
1. The PackagesResourceConfig param enables your to do automatic discovery of your relevant classes as long as you provide the packages location.
2. The url pattern is the endpoint where your resources will be made available.
The RESTful resource
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package net.tmro.demo.json;
 
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
 
@Path(/myresource”)
public class MyResource {
 
	public MyResource() {
	}
 
	@GET
	@Produces(value=MediaType.APPLICATION_JSON)
	@Path(/getsomething”)
	public MyComplexObject getSomething(@QueryParam(“idOfSomething”) String id) {
		//your complex object can expose primitive data types, objects as well as collections.
		//you are not required to do anything fancy as long as you implement
		return new MyComplexObject(id);
	}
}
To get something your endpoint will now look like: http://yourserver:port/appcontext/webappjson/myresource/getsomething?ifOfSomething=id The parts in bold represent what you’ve defined so far.
The @Get annotation specifies what type of requests are handled by this method.
The @Path allows you to discriminate between several methods that you might have in this resource class.
If in your @Produces you were to specify a MediaType.APPLICATION_XML you’d get a neat xml response when pointing your browser at the endpoint above. But what we actually want is a JSON message. So let’s continue.
JSON MessageBodyWriter
The xml returned by our resource needs to be converted into JSON format. I used the json-lib that I mentioned above. Here’s the code for it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package net.tmro.demo.json;
 
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
 
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.*;
import javax.ws.rs.ext.*;
 
import com.sun.jersey.spi.resource.Singleton;
 
import net.sf.json.JSONSerializer;
 
@Provider
@Singleton
public class MyEntityProvider implements MessageBodyWriter<object> {
	//the json serializer used to write out objects to the output stream
	private final JSONSerializer serializer = new JSONSerializer();
 
	public long getSize(final Object t, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
		return -1;
	}
 
	public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
		return mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE);
	}
 
	public void writeTo(final Object t, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType, final MultivaluedMap<string, Object> httpHeaders, final OutputStream entityStream) throws IOException, WebApplicationException {
		entityStream.write(serializer.toJSON(t).toString().getBytes());
	}
}
Not much going on here: we implement the MessageBodyWriter interface and we only use this entity provider to handle JSON mime types.
Note that the class is annotated @Provider so make sure that you have specified this package in your web.xml deployment descriptor.
Returned objects
The only thing that is still missing is the actual object that is returned. Here is an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package net.tmro.demo.json;
 
@XmlRootElement
public class MyComplexObject extends AnotherObject {
 
	//fields: primitive data types, objects and collections. everything gets serialized unless
	//marked as transient
 
	public MyComplexObject(String id){
	[..]
	}
 
	//getters and setters
}
The only thing that I have done really is to annotate it with @XmlRootElement. If you have properties that you do not want to return simply annotate them with @XmlTransient.
Now build and deploy your application and keep an eye on the log. You should see:
- Scanning for root resource and provider classes in the packages:
and then a list of your packages defined in the web.xml
Root resource classes found:
followed by your Resource class.
Provider classes found:
followed by the entity provider that you have implemented.
To test just point your browser to the url I described above and your browser should prompt you to save some streamed data. Open it with a text viewer and you should be able to see your JSON response.
Cheers…
Before I conclude: if you’ve tried to get things going and ended up with something like this:
com.sun.jersey.spi.container.ContainerResponse write
SEVERE: A message body writer for Java type, class [..], and MIME media type, application/json, was not found
com.sun.jersey.server.impl.application.WebApplicationImpl onException
SEVERE: Internal server error
javax.ws.rs.WebApplicationException
at com.sun.jersey.spi.container.ContainerResponse.write(ContainerResponse.java:241)
you might want to check that your jaxb and json lib versions are OK and that the MessageBodyWriter implementation is picked up when you start your web app…
I would be interested to find out if you managed to find a way to NOT implement the MessageBodyWriter but still get JSON output.

Unit Test JAX-RS using Java 6 and JUnit 4

Wednesday, March 25th, 2009

Today I was amazed to discover that Unit testing JAX-RS resources with JUnit 4 and Java 6 is insanely easy.

Have a look at the example below and then read the description underneath if things are not clear enough already.

import static org.junit.Assert.*;

import java.io.*;
import java.net.*;

import javax.ws.rs.*;

import org.junit.*;

import com.sun.jersey.api.container.httpserver.HttpServerFactory;
import com.sun.net.httpserver.HttpServer;

@Path("/hellotest")
public class MyResourceTest {

    private static final String LOCALHOST = "http://localhost:9998/";

    private static HttpServer server;

    @GET
    @Produces("text/plain")
    public String testSystem(){
        return "Hello. This is a test";
    }

    @BeforeClass
    public static void setUp() throws Exception{
        System.out.println("Creating server");
        server = HttpServerFactory.create(LOCALHOST);

        System.out.println("Starting server");
        server.start();

        System.out.println("HTTP server started");
        System.out.println("Running tests...");

        testResourceAtUrl(new URL(LOCALHOST + "hellotest"));
    }

    private static String testResourceAtUrl(URL url) throws Exception {

        try {
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setRequestMethod("GET");
            connection.connect();

            InputStream inputStream = connection.getInputStream();

            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String firstLineOfText = reader.readLine();//you can also read the whole thing and then test
            System.out.println("Read: " + firstLineOfText);

            System.out.println("System was initialized correctly. About to run actual tests...");

            connection.disconnect();

            return firstLineOfText;

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (ProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        throw new Exception("could not establish connection to " + url.toExternalForm());
    }

    @Test
    public void testMyMethod() throws Exception {
        String activationText = testResourceAtUrl(new URL(LOCALHOST + "myresource"));

        //TODO test here

    }

    /**
    * Destroy the server
    */
    @AfterClass
    public static void tearDown() throws IOException{
        System.out.println("Stopping server");
        server.stop(0);
        System.out.println("Server stopped");
    }

}

So here’s what the code above means:
1. @Path(“/hellotest”) The unit test itself is set up as a resource so when the tests are run we can check that the system is working by consuming the resource defined by testSystem()
2. Java 6 allows us to set up a HTTP server very easily using  HttpServerFactory.create(LOCALHOST) This way we simply go ahead and send HTTP requests without having to worry about 3rd party libs and setting up mock HTTP servers.
3. testResourceAtUrl(new URL(LOCALHOST + “hellotest”)) does the hard work: it requests the resource from the location that we specify in the method call.  
4. put your actual test data in the placeholder ;)

Of course this is a simplified test, and it is meant just to show you how easy it is to test your RESTful webservices. How would you make this better?

Cheers…