This article gives a step by step set of instructions to set up
Eclipse to run a
Jetty application container using
Jersey RESTful annotations and talk to a
MySQL database. You would have thought that with all these technologies being really popular there would be loads of really helpful documentation and help but in reality the forums of the internet are overflowing with people having trouble with this. So let’s start from the beginning and see if we can’t work through it together - ok with me doing all the work.
For the purposes of simplicity we’ll be installing all the software into the
c:\java folder.
First up we’ll install
Eclipse. We are going to create a
Dynamic Web Project. We must install the
JEE build of
Eclipse because it comes with all the supporting dependencies that we need so there won’t be many additional plugins we’ll have to install. Just for your records I did this with
Java EE IDE for Web Developers Helios Service Release 2 Build id: 20110218-0911.
- Head over to the Eclipse download page at: http://www.eclipse.org/downloads/
- We want the Eclipse IDE for Java EE Developers which comes in at a whopping 206 MB, one of the larger builds. Thanks to my lovely 50MB Virgin broadband it only takes a couple of seconds!
- Unzip the downloaded package eclipse-jee-helios-SR2-win32.zip into
c:\java\eclipse.
- Run up Eclipse and select
c:\java\workspace as the …erm workspace!
I thought that running
Jetty inside
Eclipse would be like running
Tomcat in Eclipse. I spent quite a long time looking for something that let you launch
Jetty from a pre-installed installation and was represented in the
Eclipse platform as a server. I found
JettyLauncher which does this job. On
JettyLauncher’s main sourceforge page it says that the project has closed down and we should use
Run Jetty Run instead.
Run Jetty Run installs into
Eclipse as a plugin so there is no need to have a separate
Jetty installation. The whole thing runs as an embedded program and so the integration is really tight.
Installing the
Jetty plugin couldn’t be easier.
- Load Eclipse in.
- From the menu bar select Help -> Install New Software…
- Click the Add… button to add a new repository.
- For the Name enter Run Jetty Run
- for the Location enter
http://run-jetty-run.googlecode.com/svn/trunk/updatesite
- then click Ok.
- Eclipse will go to the repository and download a list of the installable that can be downloaded. Expand them all and check the option with the highest version number. At the time of writing it is: Run Jetty Run 1.2.1.1.
- Click Finish to download and install it.
The
Java JEE build of
Eclipse has the correct configuration for us to create a
Dynamic Web Project. From the menu bar select
File -> New -> Dynamic Web Project.
Set the following options on the project set up page:
- Project name = carshare
- Target runtime = <None>
- Dynamic web module version = 3.0
- Configuration = JavaServer Faces v2.0 Project (this is really up to you)
- Select Next
- On the Web Module page, check the box for Generate web.xml deployment descriptor. This creates a starting
web.xml file for you. Without this, the system is difficult to configure down the line.
- If you selected JavaServer Faces v2.0 Project then you will have to choose an implementation to use. Click the download button (which looks like a floppy disc with a down arrow next to it) and select Apache’s Myfaces JSP Core-2.0 implementation. The first time I did this it said “failed to open zip", so I tried again and it worked!
- Clicked Finish and let it whoor away.
Now that we have an
Eclipse project we can start loading up the webapp’s lib directory with dependencies for you to use.
I have selected
Jersey as my
REST implementation because it is more compliant with
JSR311 and is properly maintained by the real Java people.
It is not completely obvious which distribution to download because they don’t have names! They only have long wordy descriptions. So download the one which is described as: “A zip of Jersey containing the Jersey jars, core dependencies (it does not provide dependencies for third party jars beyond the those for JSON support) and JavaDoc”
Uncompress it to
c:\java\jersey-archive-1.6 and copy all the jar files from
c:\java\jersey-archive-1.6\lib to
c:\java\workspace\carshare\WebContent\WEB-INF\lib.
While we are here we’ll install the
MySQL driver jar as well.
- Hop over to MySQL’s connector/J download page: http://dev.mysql.com/downloads/connector/j/
- If you can read tar.gz files then you might as well get that version because it is 200K smaller.
- Uncompress it and copy the mysql-connector-java-5.1.15.jar file into
c:\java\workspace\carshare\WebContent\WEB-INF\lib
When you have everything in place select the project name, right click and select
Refresh. Right click again (on the project name) and select
Validate (not really sure what this does but it sounds like you should do it!).
Before diving head long into databases and all the rest of it we will make sure our
Jersey REST bit works by creating a simple
POJO and
decorating it with some
JSR311 REST annotations.
- Right click on the src root package and create a new package calling it
uk.co.bigsoft.carshare.
- Once the package is created, right click on it and select New -> Class.
- Call the class
Person.
- Enter the following java code into the
Person class:package uk.co.bigsoft.carshare;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/person")
public class Person{
@GET
@Path("/list")
@Produces(MediaType.TEXT_HTML)
public String sayHtmlHello() {
return "<html><body><h1>" + "Hello MrN" + "</h1></body>";
}
}
- Save the class.
Lets have a look at the annotations. They are pretty straightforward.
- @Path - to get to this class go to
/person, to go to the sayHtmlHello() method go to /person/list.
- @GET - type of request. So you can have @POST, @DELETE and @PUT.
- @Produces - take the return type and renders it automatically into the type you specify. If you change the
MediaType to APPLICATION_JSON and return a POJO instead, Jersey will automatically convert it to JSON without any extra coding. There is also a @Consumes to handle data coming inwards.
We need to register
Jersey as the servlet dispatcher for REST requests so update the
c:\java\workspace\carshare\WebContent\WEB-INF\web.xml to include the following XML.
<servlet>
<servlet-name>Jersey REST 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>uk.co.bigsoft.carshare</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
The package
uk.co.bigsoft.carshare is the top level package. All classes and sub-packages will be searched for classes that have been annotated with …erm annotations! All
@Paths will appear under the
/rest/ URL, so with the example above the URL path will be
/rest/person/list.
If you have done it correctly you will see
Jersey REST Service under
<eclipse-project> -> Deployment Descriptor: uk.co.bigsoft.carshare -> Servlets and
/rest/* -> Jersey REST Service under
<eclipse-project> -> Deployment Descriptor: uk.co.bigsoft.carshare -> Servlet Mappings.
Now we are ready to run. From the menu select
Run -> Debug Configurations. Highlight
Jetty Webapp, right click and select
New. Everything will be automagically filled in for you so just click
Debug.
Jetty will start up inside Eclipse so using your favourite browser navigate to:
http://localhost:8080/carshare/rest/person/list and you should see the text “Hello MrN".
Happy that everything is in place we can configure the webapp to talk to
MySQL. This took me all day to solve. For such a common set of technologies there is little or no documentation. The information I found was on forums, mail lists and
Stack Overflow. All the information I found was wrong and it was just a fluke I hit the right answer with a bit of trial and error.
We have already installed the
MySQL Connector/j so all that is left to do is add the configuration. We are going to add
MySQL as a
JNDI datasource. Edit the
c:\java\workspace\carshare\WEB-INF\web.xml in
Eclipse and add the following lines:
<resource-ref>
<description>My DataSource Reference</description>
<res-ref-name>jdbc/carshare</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource>
That defines a resource called
jdbc/carshare and the interface it uses, but we need to define what the resource actually looks like. This part of the configuration is somewhat container specific so we need to put it into a separate file. All the documentation says to use
WEB-INF/jetty-env.xml but this is actually ignored by
Jetty so you have to call it
c:\java\workspace\carshare\WEB-INF\jetty-web.xml.
Next, create the following context definition:
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<configure class="org.mortbay.jetty.webapp.WebAppContext">
<new id="carshare" class="org.mortbay.jetty.plus.naming.Resource">
<arg></arg>
<arg>jdbc/carshare</arg>
<arg>
<new class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<set name="Url">jdbc:mysql://localhost:3306/carshare</set>
<set name="User">mrn</set>
<set name="Password">hard2crack</set>
</new>
</arg>
</new>
</configure>
And now for the final stage. We need to call an instance of the datasource into existence from inside our RESTful class.
All the documentation I read said you just have to add:
InitialContext ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/carshare");
to your code and it would all work. Well every time a called
new InitialContext() it returned an empty (or blank)
Context so my lookup always failed. To get around this you need to add a
c:\java\workspace\carshare\WEB-INF\lib\jndi.properties containing some magic “make-it-work” lines
java.naming.factory.url.pkgs=org.mortbay.naming
java.naming.factory.initial=org.mortbay.naming.InitialContextFactory
Add
jetty-name-ver.jar and
jetty-plus-ver.jar to
WEB-INF/lib as well.
Finally the name I was getting the exception:
java:comp/env/jdbc/carshare javax.naming.NameNotFoundException; remaining name ‘env/jdbc/carshare’
All the
Jetty documentation says that if you name the resource
jdbc/carshare then
Jetty’s context will automatically add the
java:comp/env so it fits in with other application containers. This was not my experience. The only name I could look up was
jdbc/carshare. So I changed the code to the following and all was good.
InitialContext ctx = new InitialContext();
ds = (DataSource) ctx.lookup("jdbc/carshare");
There is no way I could have done this without the help of the following articles and a bit of
luck!
Jersey + eclipse: http://www.vogella.de/articles/REST/article.html
Install run-jetty-run: http://code.google.com/p/run-jetty-run/wiki/GettingStarted
http://stackoverflow.com/questions/2131798/jetty-mysql-connection-pool-configuration-error-javax-naming-namenotfoundexcepti