miércoles, noviembre 18, 2009

Jersey Tomcat REST: servlet-mapping POST GET example

Have had a hard time on something that should be plain simple. That is combining HTML and Jersey Resources on a single apache tomcat project.

On the web.xml file we specify how we want the servlets to serve the content. What comes here, what goes there.

I want to serve both
http://localhost/quiztest/index.html
which is my HTML initial file, and also provide
http://localhost/quiztest/thing/stuffpost
http://localhost/quiztest/thing/stuffget
resources, which are two versions get and post of the Resource.

So if I tried to set servlet-mapping to get everything to the servlet container that serves Jersey resources like:

<servlet>
<servlet-name>JerseyTest</servlet-name>
<servlet-class>com.sun.jersey.server.impl.container.servlet.ServletAdaptor</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JerseyTest</servlet-name>
<url-pattern>/thing/*<url-pattern>
</url-pattern>
</url-pattern></servlet-mapping>



Then I could serve the resources - but the index.html wasn't served. Sure, this is not the preferred way: I don't want *all* of my requests to go to the ServletAdaptor. Then I do:

<servlet>
<servlet-name>JerseyTest</servlet-name>
<servlet-class>com.sun.jersey.server.impl.container.servlet.ServletAdaptor</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JerseyTest</servlet-name>
<url-pattern>/thing/*<url-pattern>
</url-pattern>
</url-pattern></servlet-mapping>


to make only the requests of the kind http://localhost/quiztest/thing... go to the servlet. The way to go.

It didn't work.

The Resources were not served. Same with other url-patterns. This has got me quite crazy for some time. It should work according to the definition of servlet-mapping. I gotta say that I haven't quickly found any reasonably authoritative source where the definition of the matching algorithm is, so I don't linked to any.

Bad thing is the solution hasn't been stylish at all:

<servlet>
<servlet-name>JerseyTest</servlet-name>
<servlet-class>com.sun.jersey.server.impl.container.servlet.ServletAdaptor</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JerseyTest</servlet-name>
<url-pattern>/thing/stuffpost<url-pattern>
</url-pattern>
<servlet-mapping>
<servlet-name>JerseyTest</servlet-name>
<url-pattern>/thing/stuffget<url-pattern>
</url-pattern>
</url-pattern></servlet-mapping></url-pattern></servlet-mapping>


And voilà, this works. I really don't understand why this is behaving like this. Maybe there is some kind of bugs on the handling of the requests to resources. Or maybe the names of the resources are to be matched completely to be served since they are not in the directory tree.
I'm too lazy to look at the code to satisfy my thirst of knowledge. I'm actually going to satisfy my hunger - it's lunch time already!

Thanks to Surya for his post that helped setting up the things.

The helloworld-ish dead simple resource code below. To test it, create an index.html with a post form that sends that parameter "param1" below (see POST method).

package com;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("thing")
public class YoTest
{
@GET
@Produces("text/html")
@Path("stuffget")
public String catGet()
{
return "This is stuffget.";
}

@Consumes("application/x-www-form-urlencoded")
@POST
@Produces("text/html")
@Path("stuffpost")
public String catPost(
@FormParam("param1") Integer value1 )
{
return "Your final POST value: " + value;
}

}


Then my structure is something similar to the one below. I've simplified some of the things in folders and so on.

WebContent:


-- WebContent
| |-- 403.html
| |-- 404.html
| |-- 500.html
| |-- META-INF
| | `-- MANIFEST.MF
| |-- WEB-INF
| | |-- classes
| | | `-- com
| | | `-- YoTest.class
| | |-- lib
| | | |-- asm-3.1.jar
| | | |-- jersey-client-1.1.0-ea.jar
| | | |-- jersey-core-1.1.0-ea.jar
| | | |-- jersey-guice-1.0.3.jar
| | | |-- jersey-json-1.1.0-ea.jar
| | | |-- jersey-server-1.1.0-ea.jar
| | | `-- jsr311-api-1.1.jar
| | `-- web.xml
| |-- css
| |-- index.html
| `-- javascript

6 comentarios:

fettuchini dijo...

My pencil and my book is in the desk (are)
My pencil and my book are in the desk (on)
My pencil and my book are on the desk (thats right man!)
My pencil and my book are on the desk, thats right man.
My tailor is rich and my mothers in the kitchen
My tailor is rich and my mothers in the ketch
Every children play football in the camp
Everybody play football in the camp
And I play to my dog because I want to
All the girls every day, everywhere, everybody
I am your
My tailor is rich and my mothers in the kitchen
My tailor is rich and my mothers in the kitchen
Pretty kitty like the milk (likes milk)
Pretty kitty likes milk
Big dog likes kitty pretty
The butyl is little, the teacher is tall
My tailor is rich and my mothers in the kitchen
My tailor is rich and my mothers on the kitchen
On the desk
Hello, my name is Mary Wilson, I am 24 years old
I dont remember what is Meridian Street
And I like to sing in spring
On the desk

Xmariachi dijo...

The Dead Bullfighters my friend.

Good that you didn't add links, otherwise it would look like spam.

El Abuelo dijo...

It isn't very clear for me after reading the post. Wich football team won the match?

Xmariachi dijo...

I think that point was made quite clear in the text, especially on my criticism to the strategy applied by the coach.

Now that I think a bit, is it a casuality that New Jersey's NBA team is called the Nets? Or a long-run merchandise from Sun?

diät pillen dijo...

Mapping everything under my context path to the front controller (let's call it "app") means I should take care of static files also, something I'd rather not to (why reinvent yet another weel?), so some combination with tomcat's default servlet (let's call it "tomcat") appears to be the way to go.

Xmariachi dijo...

Hi diät,

Yes, this is an example where there is no web server serving static content but all within tomcat. This is for the sake of the document, since in production is better to have a web server like apache or jetty taking care of the static content and passing the servlet requests to tomcat only.

By the way, I think this all comes because the jersey paths themselves are virtual (that is, there is no real path through folders / files that leads to the content). I think the servlet-mapping directive checks this and then it needs to match exactly the relative path - not a substring of it. It should, but it looks more of a Jersey specificity than a servlet-mapping implementation error.