Jetty est un conteneur de servlets open source, ce qui signifie qu’il permet de servir du contenu web fait avec des servlets et des JSPs.

Jetty est ecrit en Java et ses APIs sont disponibles dans un groupe de JARs. Les developpeurs peuvent instantier dans une application Java stand-alone un conteneur Jetty comme un objet, ajouter ensuite de la connectivite reseau et web.

Apache Tomcat est de loin le conteneur de servlet open source le plus connu. Pourtant, Tomcat n’est pas le seul dans ce monde : il y a aussi Jetty. Avoir une autre possibilité pour un conteneur de servlets est un plus, mais l’avantage de Jetty est qu’il peut etre embedded dans du code Java.
Les développeurs livrent Jetty comme un ensemble de JARs de facon a ce que l’on puisse instantier et manipuler un conteneur de servlet dans son propre code. Ca peut ouvrir de nouvelles possibilités.

Ainsi , un premier exemple qui me vient a l’esprit est :
Faire une application Java stand alone pour une messagerie instantanée (type Yahoo Messenger), et ouvrir la possibilite d’envoyer et recevoir des fichiers sur HTTP sans avoir a passer par un serveur intermediaire.
Pour cela il suffirait d’embarquer Jetty dans la web app, pour heberger la servlet receptrice du document. Cote client, privilegier une API comme Http Client pour poster vers la servlet distante.

On peut supooser vouloir creer son propre serveur d’application Java EE.
Si on se refere aux specs, un tel serveur d’applications doit supporter servlets , EJB et autres fonctionnalites.
Plutot que creer un conteneur de servlet from scratch, il suffirait d’integrer Jetty. C’est exactement ce que les equipes derriere Apache Geronimo, JBoss ou ObjectWeb JOnAS ont fait pour creer leurs serveurs d’applications Java EE.
Les testeurs pourraient creer egalement un conteneur a la demande , quand il n’est pas possible d’obtenir des serveurs d’applications pré-configurés.

Si notre job est de vendre des applications web, pourquoi ne pas livrer aux clients un fichier WAR et ajouter un conteneur spécifique. Ainsi, on peut livrer les applications avec leurs propres fonctionnalités de start, stop et d’administration.

Meme les vendeurs de hardware peuvent en beneficier:
Jetty a une empreinte memoire faible — seulement 350kb pour un service HTTP (sans servlets).
Ils pourraient fournir ainsi des panneaux de controle Web en beneficiant de la puissance de Java, et sans le poids d’un serveur d’applications séparé.

Setup

Le premier exemple va montrer un simple service Jetty.
On va instantier un conteneur de servlets, mapper une classe servlet vers une URI, puis on va invoquer au moyen d’un navigateur l’URL.

Downloader une version 5.X.X de Jetty a l’adresse http://jetty.mortbay.org/jetty/download.html (en ce moment, la version stable etant la 5.1.11)

Extraire Jetty le contenu de l’archive dans un repertoire de votre choix, qu’on notera $JETTY_HOME.

Créer un répertoire pour héberger le projet : $WORKSPACES/JettyDemo

Embarquer les librairies de Jetty et dépendances dans le projet :

Copier dans un le répertoire $WORKSPACES/JettyDemo/jetty-5.1.11 les JARs suivants :

$JETTY_HOME/javax.servlet.jar

$JETTY_HOME/org.mortbay.jetty.jar

$JETTY_HOME/commons-el.jar

$JETTY_HOME/commons-logging.jar

$JETTY_HOME/jasper-compiler.jar

$JETTY_HOME/jasper-runtime.jar

$JETTY_HOME/log4j-1.2.11.jar

$JETTY_HOME/xercesImpl.jar

$JETTY_HOME/xml-apis.jar

$JETTY_HOME/xmlParserAPIs.jar

Créer le répertoire $WORKSPACES/JettyDemo/src pour accueillir vos sources.

Lancer un IDE (dans mon cas Eclipse) : Créer le projet JettyDemo (mappé sur $WORKSPACES/JettyDemo) . Automatiquement toute l’arborescence du projet incluant les JARs devraient apparaitre dans le projet comme suit:

Créer une servlet dans $WORKSPACES/JettyDemo/src/sample : SimpleServlet.java

import java.io.IOException;
import java.io.PrintWriter ;

import javax.servlet.http.HttpServlet ;
import javax.servlet.ServletConfig ;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest ;
import javax.servlet.http.HttpServletResponse ;

public class SimpleServlet
extends HttpServlet
{

public void init( ServletConfig config )
throws
ServletException
{
super.init( config ) ;
} // init

public void doGet( HttpServletRequest request , HttpServletResponse response )
throws
ServletException ,
IOException
{

final String pathInfo = request.getPathInfo() ;
PrintWriter out = new PrintWriter( response.getWriter() ) ;
out.print( “Servlet called: ” ) ;

if( null == pathInfo ){
out.println( “no extra path info” ) ;
} else {
out.println( “path info is \”" + pathInfo + “\”" ) ;
}
return ;

} // doGet()

}

Créer un programme qui lance le conteneur Web et enregistre la servlet :

Avant de montrer le source complet, quelques explications :

L’objet Service est le conteneur Jetty. En instantiant l’objet, on crée le conteneur :

Server service = new Server() ;

A ce stade , on ne peut pas utiliser le conteneur. Le code suivant montre comment ajouter un listener, qui ecoute sur localhost, port 7501
service.addListener( “localhost:7501″ ) ;

Pour mapper une simple servlet, créer un contexte a la volée avec appel de la méthode getContext() sur l’objet Service.
Le code suivant crée simplement un contexte nommé /embed

ServletHttpContext ctx = (ServletHttpContext)
service.getContext( “/embed” ) ;

Ensuite, appeler addServlet() pour mapper la servlet à une URI :

ctx.addServlet(
“Simple” , // servlet name
“/TryThis/*” , // URI mapping pattern
“sample.SimpleServlet” // class name
) ;

Le premier parametre correspond au nom de la servlet. Le second est un chemin mappé, equivalent au tag dans le fichier web.xml. Ce chemin est relatif au path du contexte, /embed.
Le “/*” signifie que la servlet va accepter tous les appels sur /embed/TryThis aussi bien que tout ce qui commence par cette URI, par exemple /embed/TryThis/123

Le conteneur est encore au statut idle a ce moment la. Il n’a pas encore été bindé a la socket listener.
Pour démarrer le conteneur :

service.start() ;

Cette méthode redonne la main immédiatement, puisque Jetty lance le service dans un thread séparé.

L’arrêt du service est très simple :

service.stop() ;

Code complet :

package sample;

import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.ServletHttpContext;

public class Demo1 {

private static final String LISTEN_ADDY = “localhost:7501″ ;
private static final String CONTEXT_PATH = “/embed” ;

private static final String SERVLET_CLASS = “sample.SimpleServlet” ;
private static final String SERVLET_PATH = “/TryThis” ;
private static final String SERVLET_MAPPING = SERVLET_PATH + “/*”;

public static void main( final String[] args ) {

try{

// represents a container
final Server service = new Server() ;

// configure container to listen on a given socket for requests
service.addListener( LISTEN_ADDY ) ;

// define a web application at a given context path
ServletHttpContext ctx = (ServletHttpContext) service.getContext( CONTEXT_PATH ) ;

// map a servlet class to a URI
ctx.addServlet(
“Simple” ,
SERVLET_MAPPING ,
SERVLET_CLASS
) ;

// start the container. Notice that this call returns immediately;
// Jetty handles the threading for you behind the scenes. All you
// have to do is hold on to the Server object such that you can
// shut it down later.

service.start() ;
System.out.println( “Server started” ) ;

}catch( Throwable t ){
t.printStackTrace() ;

// without the explicit exit() call, the container’s threads would
// continue to run ad infinitum. In a real app, the catch() block
// would call Server.stop() in a do-nothing try/catch block, not
// unlike one used for a JDBC ResultSet or Statement.
System.exit( 1 ) ;
}

} // main()

}

Externaliser la configuration :

On peut simplifier drastiquement le lanceur du conteneur et garder un code propre en externalisant dans un fichier XML toute la configuration.

Voici le code simplifié du lanceur :

public class Demo2 {

public static void main( final String[] args ) {

try{

// load config from a file in the classpath
final URL serviceConfig = Thread.currentThread().getContextClassLoader().getResource( “service-config.xml” ) ;
final XmlConfiguration serverFactory = new XmlConfiguration( serviceConfig ) ;

// represents a container
final Server service =

// instantiate a Server object based on the XML config file
(Server) serverFactory.newInstance() ;

// start the container. Notice that this call returns immediately;
// Jetty handles the threading for you behind the scenes. All you
// have to do is hold on to the Server object such that you can
// shut it down later.

service.start();
System.out.println( “Server started” ) ;

}catch( Throwable t ){
t.printStackTrace() ;

System.exit( 1 ) ;
}

} // main()

}

Le fichier de configuration se décompose ainsi :


Déployer une Web Application:

Nous avons vu comment déployer une servlet, il est possible de déployer une web application packagée dans un WAR.

Pour cela, il suffit d’ajouter dans le fichier de config le fragment XML suivant (au meme niveau que l’appel a getContext() ):

Exécuter en ligne de commande :

Il est possible d’utiliser le JAR start.jar (venant avec la distro de Jetty)

Pour avoir l’equivalent du lanceur Demo2.java il suffit d’exécuter dans un terminal :

CLASSPATH=…liste des jars Jetty…

java \

-Djetty.class.path=${CLASSPATH} \

-jar /start.jar \

service-config.xml

Ressources:

Code sample

Jetty Home