samedi 15 décembre 2012

Run background process for your Maven integration tests

The Maven Failsaif plugin makes it very simple to run integration test written with JUnit or TestNG. This example shows how to use the Maven Failsafe Plugin to run Integration Tests that properly starts and stop a Jetty server during both the pre-integration-test phase and the post-integration-test phase. This solution can be easyly derivated to start and stop any background process that is well integrated as a Maven plugin :
<plugin>
    <groupId>${plugin.groupId}</groupId>
    <artifactId>${plugin.artifactId}</artifactId>
    <version>${plugin.version}</version>
    <configuration>
        <anything>...</anything>
    </configuration>
    <executions>
        <execution>
            <id>do-it-before</id>
            <phase>pre-integration-test</phase>
            <goals>
                <goal>${plugin.start.goal}</goal>
            </goals>
            <configuration>
                <something>...</something>
            </configuration>
        </execution>
        <execution>
            <id>do-it-after</id>
            <phase>post-integration-test</phase>
            <goals>
                <goal>${plugin.stop.goal}</goal>
            </goals>
            <configuration>
                <whatever>...</whatever>
            </configuration>
        </execution>
    </executions>
</plugin>
Sometimes, there is no plugin or maven integration that you can use to start and stop the background process(es) required by your intergation test case to run. You can start and stop the desired process(es) manually but let see how to do this properly with Maven.

Maven exec plugin

The Maven exec plugin provides 2 goals to help execute system and Java programs. However, the programs execution are blocking. It is thus impossible to run tests during the intergation-test phase with running programs started during the pre-integration-test phase. Hopefully, the Maven antrun plugin will help us...

Maven antrun plugin

The Maven antrun plugin provides the ability to run Ant tasks from within Maven. It can do anything you can put into an ant build.xml script. In particular, it is possible to use the Ant exec task with all its parameters. The solution to our problem is the spawn parameter of the exec task that will run the specified executable asynchronously in its own process :
<exec executable="command-to-run"
      dir="base/dir/for/the/command"
      spawn="true"> <!-- run it asynchronously and in background baby -->
    <arg value="arg"/>
    <arg value="arg"/>
    ...
    <arg value="arg"/>
</exec>
Okay but now, we want to start third parties programs with the Maven antrun plugin during the pre-integration-test phase, keeping them running during the integration-test phase and to shut them down during the post-integration-test phase. Assuming we have plateform dependent scripts to start and stop Zookeeper, Kafka or anything else... our pom.xml will look like this :
<plugin>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>start-third-parties</id>
            <phase>pre-integration-test</phase>
            <configuration>
                <target>
                    <exec executable="${run.command}"
                          dir="${basedir}/../scripts"
                          spawn="true">
                        <arg value="${run.command.additionnal.arg}"/>
                        <arg value="${basedir}/../scripts/${zookeeper.start.script}"/>
                    </exec>
                    <exec executable="${run.command}"
                          dir="${basedir}/../scripts"
                          spawn="true">
                        <arg value="${run.command.additionnal.arg}"/>
                        <arg value="${basedir}/../scripts/${kafka.start.script}"/>
                    </exec>
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
        </execution>
        <execution>
            <id>stop-third-parties</id>
            <phase>post-integration-test</phase>
            <configuration>
                <target>
                    <exec executable="${run.command}"
                          dir="${basedir}/../scripts"
                          spawn="false">
                        <arg value="${run.command.additionnal.arg}"/>
                        <arg value="${basedir}/../scripts/${zookeeper.stop.script}"/>
                    </exec>
                    <exec executable="${run.command}"
                          dir="${basedir}/../scripts"
                          spawn="false">
                        <arg value="${run.command.additionnal.arg}"/>
                        <arg value="${basedir}/../scripts/${kafka.stop.script}"/>
                    </exec>
                </target>
            </configuration>
            <goals>
                <goal>run</goal>
            </goals>
       </execution>
    </executions>
</plugin>
There is no need to spawn the shutdown of our third parties programs, but it's possible too...

Okay but what if I want to use both Linux and Windows ?

No problem ! Maven profiles are here to help you. You just have to define two profiles wich <activation> relies on the os family like this :
<profile>
    <id>windows-properties</id>
    <activation>
        <os>
          <family>Windows</family>
        </os>
    </activation>
    <properties>
        <run.command>cmd</run.command>
        <run.command.additionnal.arg>/c</run.command.additionnal.arg>
        <zookeeper.start.script>start-zookeeper.bat</zookeeper.start.script>
        <zookeeper.stop.script>stop-zookeeper.bat</zookeeper.stop.script>
        <kafka.start.script>start-kafka.bat</kafka.start.script>
        <kafka.stop.script>stop-kafka.bat</kafka.stop.script>
    </properties>
</profile>
<profile>
    <id>linux-properties</id>
    <activation>
        <os>
          <family>unix</family>
        </os>
    </activation>
    <properties>
        <run.command>sh</run.command>
        <run.command.additionnal.arg></run.command.additionnal.arg>
        <zookeeper.start.script>start-zookeeper.sh</zookeeper.start.script>
        <zookeeper.stop.script>stop-zookeeper.sh</zookeeper.stop.script>
        <kafka.start.script>start-kafka.sh</kafka.start.script>
        <kafka.stop.script>stop-kafka.sh</kafka.stop.script>
    </properties>
</profile>
Et voila, the start and stop scripts properties will be set correctly depending on the runtime OS.

Okay but I don't want to run whole intergation tests all the time ?

This time again, you can use a Maven profile but without <activation>. Plugins will be activated only if you specify the profile inside the maven command :
mvn clean install -P integration-tests
<profiles>
    <profile>
        <id>integration-tests</id>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-failsafe-plugin</artifactId>
                    <version>2.12.2</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>integration-test</goal>
                                <goal>verify</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <artifactId>maven-antrun-plugin</artifactId>
                    <version>1.6</version>
                    <executions>
                        <execution>
                            <id>start-third-parties</id>
                            <phase>pre-integration-test</phase>
                            <configuration>
                                <target>
                                    <!-- ANT stuff -->
                                </target>
                            </configuration>
                            <goals>
                                <goal>run</goal>
                            </goals>
                        </execution>
                        <execution>
                            <id>stop-third-parties</id>
                            <phase>post-integration-test</phase>
                            <configuration>
                                <target>
                                    <!-- ANT stuff -->
                                </target>
                            </configuration>
                            <goals>
                                <goal>run</goal>
                            </goals>
                       </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

About the stop scripts

Stop scripts are sometimes not easy to write... but there is always a way to kill a process ! The examples bellow are made for Kafka (replace kafka.Kafka by anything that can identify the process you started) :

on Linux

ps ax | grep -i 'kafka.Kafka' | grep -v grep | awk '{print $1}' | xargs kill -SIGTERM
You may have to pay to run it on Mac OS X indeed...

on Windows

wmic process where (commandline like "%%kafka.Kafka%%" and not name="wmic.exe") delete
You only need to double '%' if you want the command to be executed within a .bat file.

Conclusion

This solution might work for a lot of third parties appliations that you might want to run in background in order to pass integration tests on your whole application layers :
  • run a queue like Kafka or ZeroMQ that doesn't provide Maven integration yet
  • run a database like MySQL, Cassandra (Maven plugin available btw...) or HBase
  • run an independent instance of anything : Memcached, ElasticSearch or Solar for example
Tell me if you use it for something else ;-)

jeudi 1 novembre 2012

Un simulateur de crédit à emporter

Aujourd'hui je vous fait partager un petit développement personnel effectué afin de tester les possibilités offertes par le framework jQuery mobile. Il s'agit d'un petit utilitaire permettant de simuler un emprunt quelconque (prêt immobilier, crédit à la consommation, ...) en précisant le montant et la durée d'emprunt, le taux d'intérêt et d'éventuelles charges additionnelles (prîmes d'assurances ou autres).

Le résultat est présenté de manière synthétique sous forme de popup avec le montant de la mensualité, le total des intérêts, le taux effectif global et le coût total du crédit. Une vue détaillée par mensualité permet de visualiser le détail des intérêts, du montant remboursé et du montant restant à rembourser. Voici le résultat :


Vous pouvez également faire le test sur votre smartphone ou tablette

dimanche 23 septembre 2012

Mahout Taste walkthrough (initiation par l'exemple)

Ce post à pour objectif de défricher le fonctionnement du moteur de recommandation d'Apache Mahout Taste en étudiant les projets d’exemples fournis avec la version 0.7 d'Apache Mahout (L'API est susceptible d'évoluer en profondeur tant que la MileStone 1 n'est pas atteinte).
<dependency>
    <groupId>org.apache.mahout</groupId>
    <artifactId>mahout-core</artifactId>
    <version>0.7</version>
</dependency>

<dependency>
    <groupId>org.apache.mahout</groupId>
    <artifactId>mahout-examples</artifactId>
    <version>0.7</version>
</dependency>

Concepts

Mahout Taste permet de fournir des recommandation d'Items à des User. Users et Items étant tous deux représentés par des entiers. Afin de fournir des recommandations, le framework s'appuie sur un DataModel constitué de préférences. Une préférence est un nombre flottant représentant une affinité entre un User et un Item.


Le moteur de recommandation repose sur l'interface Recommender. Les implémentations de cette interface permettent de :
  • Récupérer une liste d'Items recommandées pour un User
  • D'estimer l'affinité entre un User et un Item
  • De modifier des préférences à la volée

Un exemple simple : ItemAverageRecommender

ItemAverageRecommender est une implémentation de l'interface Recommender qui estime l'affinité potentielle entre un User et un Item comme la moyenne des affinités des User ayant exprimés une préférence pour pour cet Item. Elle permet ainsi d'obtenir des recommandations indiférenciées par User.

Le BookCrossingRecommender

Un peu plus intéressant, le BookCrossingRecommender est un exemple concret de Recommender qui s'appuie sur un jeu de données réel :
public final class BookCrossingRecommender implements Recommender {

    private final Recommender recommender;

    public BookCrossingRecommender(DataModel bcModel) throws TasteException {
        UserSimilarity similarity = new CachingUserSimilarity(
                new EuclideanDistanceSimilarity(bcModel), bcModel);
        UserNeighborhood neighborhood = new NearestNUserNeighborhood(10, 0.2, similarity, bcModel, 0.2);
        recommender = new GenericUserBasedRecommender(bcModel, neighborhood, similarity);
    }
}
En regardant de plus près le code de ce BookCrossingRecommender on remarque la présence des concepts suivants :
UserSimilarity
qui représente la ressemblance entre deux User.
UserNeighborhood
qui représente le voisinage d'un User; les voisins étant déterminés en fonction de leurs ressemblance.
Des implémentations diverses de ces deux concepts sont disponibles par défaut dans Mahout Taste. Le BookCrossingRecommender utilise la classe EuclideanDistanceSimilarity comme implémentation de la ressemblance. Celle-ci permet de classer les Users selon la distance euclidienne entre leurs affinités communes (chaque Item pour lequel ils ont chacun exprimé une préférence étant une dimension).

Une fois la notion de ressemblance posée, il est alors possible de définir le voisinage d'un User. Dans le cas du BookCrossingRecommender, le voisinage d'un User est constitué des 10 Users qui lui sont le plus ressemblant. La classe NearestNUserNeighborhood permet de fixer un seuil minimal en dessous duquel la ressemblance entre deux Users leur interdit d'être voisins.

Enfin, le GenericUserBasedRecommender est utilisé afin de proposer des recommandations à un User en considérant les Items ayant l'affinité moyenne la plus grande parmi son voisinage...

Comment choisir (construire) une bonne implémentation

Si Taste propose une API simple permettant de monter rapidement un système de recommandation sur un jeux de données quasi quelconque, comment savoir si la notion de ressemblance retenue est la bonne, si le voisinage n'a pas été choisi trop vaste ou trop restreint et si la méthode de sélection des recommandations est pertinente ?

Quelques requêtes sur Google permettent de se rendre compte que de nombreuses recherches plus ou moins compréhensibles (plutôt moins que plus) ont été menées sur le sujet.

Pour le commun des mortels, Mahout Taste est livré avec un RecommenderEvaluator sui, comme son nom l'indique, permet d'estimer la qualité d'un Recommender. A partir d'un DataModel, le RecommenderEvaluator va construire le Recommender à évaluer en utilisant une partie du jeu de données : le "training percentage". Il va ensuite évaluer le Recommender sur un sous ensemble du jeu de données appelé "evaluation percentage" et retourner une note. Plus la note retournée est basse, plus le Recommender a proposé des recommandations proches des préférences réelles de l'"evaluation percentage". Une note de 0 indiquant des résultats identiques entre les recommandations du Recommender et l'"evaluation percentage".

vendredi 13 avril 2012

Introducing jQuery dice plugin

jQuery dice plugin is a jQuery plugin that ease the inclusion of dice inside your jQuery-based website. It is based on CSS3 and Javascript and allow you to draw 2D dice of any size without using any image.


dice build using jQuery dice plugin

How to use

Include both the css and the javascript plugin into your html page :


You can then turn any <DIV> into a die by calling the dice function :
$("#die").dice({
    size: 100, // in pixels
    val: 3, // 1, 2, 3, 4, 5, 6
    rotation: 0 // O to 359 deg
});
The dice function accepts three options :
size :
The dimensions of the die in pixels (height and width are equals)
default : 100px
val :
The face of the die (1, 2, 3, 4, 5 or 6)
default : random
rotation :
The rotation of the die in degrees. The anchor point is the middle of the die.
default : 0
Test it with the jQuery mobile demo page bellow :



Only the following browser are supported yet :
  • Firefox
  • Chrome (including Android 2.3+)
  • Safari (including iPhone and iPad)

jeudi 5 avril 2012

De jolis dés en CSS3 et HTML

Grâce au CSS3, il est maintenant possible d'utiliser des effets avancés permettant de réaliser des mises en pages HTML poussées qui soient scalables et qui ne nécessitent plus de connaitre en profondeur Photoshop, Illustrator et autres Gimp, ... La seule limite reste votre créativité et votre imagination. Pour les stimuler un peu, voici comment réaliser simplement les six faces d'un dé en HTML et CSS3 :

Dés en CSS3 et HTML

Structure HTML d'une face

Prenons l'exemple du six. Pour composer cette face du dé, nous utilisons le markup HTML suivant :
<div class="dice-container">
    <div class="dice dice-6">
        <div class="dice-indicator indicator-1"></div>
        <div class="dice-indicator indicator-2"></div>
        <div class="dice-indicator indicator-3"></div>
        <div class="dice-indicator indicator-4"></div>
        <div class="dice-indicator indicator-5"></div>
        <div class="dice-indicator indicator-6"></div>
    </div>
</div>
Un conteneur pour le dé
Ce DIV sera utilisé pour appliquer la projection de l'ombre du dé sur la surface.
Un conteneur pour la face du dé
Ce DIV sera utilisé pour appliquer le dégradé de lumière relatifs à la face visible du dé.
Un conteneur par indicateur
Ce DIV sera utilisé pour chaque rond noir servant à indiquer la valeur de la face du dé. Un reflet plastique blanc lui sera appliqué afin de simuler une impression de creux dans la face du dé.

Styles appliqués

Pour simplifier la lecture des styles ci dessous, seules les compatibilités Firefox et Webkit ont été conservées. Pour une compatibilité étendue aux autres navigateurs : internet explorer 9 et opéra, il faut adapter les -webkit et -moz à leurs équivalents -ie pour internet explorer et -o pour opéra.

Dans un premier temps, nous allons appliquer au conteneur du dé, une ombre projetée :
div.dice-container {
    color: white;
    height: 100px;
    width: 100px;
    border: none;
    border-radius: 15px;
    -webkit-border-radius: 15px;
    box-shadow: -1px 1px 5px #888888;
    -webkit-box-shadow: -1px 1px 5px #888888;
}
ombre projetée du dé
Puis il faut appliquer à la face du dé deux effets distincts :
  1. Une ombre interne pour simuler l'arrondi des arrêtes du dé qui délimitent la face du dé.
  2. Une ombre radial pour simuler un effet de reflet de la lumière à la surface de la face du dé.
div.dice {
    color: white;
    height: 100px;
    width: 100px;
    border: none;
    border-radius:15px;
    -webkit-border-radius:15px;
    background: -moz-radial-gradient(right top, circle, #FFFFFF, #F6F6F6);
    background: -webkit-radial-gradient(right top, circle, #FFFFFF, #F6F6F6);
    -webkit-box-shadow: inset 2px -2px 3px 3px #EEEEEE;
    box-shadow: inset 2px -2px 3px 3px #EEEEEE;
}
Arrondi de la face du dé et reflet
L'étape suivante consiste à créer un rond noir donnant l'impression d'être creusé dans la face du dé. Pour cela, on utilise un gradient radial que l'on décale vers le bord inférieur gauche du rond noir :
div.dice div.dice-indicator {
    width: 18px;
    height: 18px;
    -webkit-box-shadow: inset 0 0 1px 1px #111111;
    box-shadow: inset 0 0 1px 1px #111111;
    background: -moz-radial-gradient(left bottom, circle, #FFFFFF, #000000, #000000); 
    background: -webkit-radial-gradient(left bottom, circle, #FFFFFF, #000000, #000000);
    -moz-border-radius: 9px;
    -webkit-border-radius: 9px;
    border-radius: 9px;
    position: relative;
}
rond noir incurvé
Pour terminer, il ne reste plus qu'à positionner les ronds noirs sur la face du dé selon la valeur souhaitée :
div.dice-1 div.indicator-1, div.dice-5 div.indicator-1, div.dice-3 div.indicator-1 {
    top: 41px; /* 41 */
    left: 41px; /* 41 */
}

div.dice-5 div.indicator-2, div.dice-3 div.indicator-2 {
    top: -2px; /* 16 */
    left: 16px; /* 16 */
}

div.dice-5 div.indicator-3 {
    top: -20px; /* 16 */
    left: 66px; /* 66 */
}

div.dice-5 div.indicator-4 {
    top: 12px; /* 66 */
    left: 16px; /* 16 */
}

div.dice-5 div.indicator-5 {
    top: -6px; /* 66 */
    left: 66px; /* 66 */
}

div.dice-2 div.indicator-1, div.dice-4 div.indicator-1 {
    top: 16px; /* 16 */
    left: 16px; /* 16 */
}

div.dice-2 div.indicator-2, div.dice-4 div.indicator-2 {
    top: 48px; /* 66 */
    left: 66px; /* 66 */
}

div.dice-3 div.indicator-3 {
    top: 32px; /* 66 */
    left: 66px; /* 66 */
}

div.dice-4 div.indicator-3 {
    top: -20px; /* 16 */
    left: 66px; /* 66 */
}

div.dice-4 div.indicator-4 {
    top: 12px; /* 66 */
    left: 16px; /* 16 */
}

div.dice-6 div.indicator-1 {
    top: 16px; /* 16 */
    left: 16px; /* 16 */
}

div.dice-6 div.indicator-2 {
    top: 23px; /* 41 */
    left: 16px; /* 16 */
}

div.dice-6 div.indicator-3 {
    top: 30px; /* 66 */
    left: 16px; /* 16 */
}

div.dice-6 div.indicator-4 {
    top: -38px; /* 16 */
    left: 66px; /* 66 */
}

div.dice-6 div.indicator-5 {
    top: -31px; /* 41 */
    left: 66px; /* 66 */
}

div.dice-6 div.indicator-6 {
    top: -24px; /* 66 */
    left: 66px; /* 66 */
}
Les dés peuvent alors être directement ajoutés au code HTML de la page au moyen du code suivant :
<div class="dice-container">
    <div class="dice dice-1">
        <div class="dice-indicator indicator-1"></div>
    </div>
</div>

<div class="dice-container">
    <div class="dice dice-2">
        <div class="dice-indicator indicator-1"></div>
        <div class="dice-indicator indicator-2"></div>
    </div>
</div>

<div class="dice-container">
    <div class="dice dice-3">
        <div class="dice-indicator indicator-1"></div>
        <div class="dice-indicator indicator-2"></div>
        <div class="dice-indicator indicator-3"></div>
    </div>
</div>

<div class="dice-container">
    <div class="dice dice-4">
        <div class="dice-indicator indicator-1"></div>
        <div class="dice-indicator indicator-2"></div>
        <div class="dice-indicator indicator-3"></div>
        <div class="dice-indicator indicator-4"></div>
    </div>
</div>

<div class="dice-container">
    <div class="dice dice-5">
        <div class="dice-indicator indicator-1"></div>
        <div class="dice-indicator indicator-2"></div>
        <div class="dice-indicator indicator-3"></div>
        <div class="dice-indicator indicator-4"></div>
        <div class="dice-indicator indicator-5"></div>
    </div>
</div>

<div class="dice-container">
    <div class="dice dice-6">
        <div class="dice-indicator indicator-1"></div>
        <div class="dice-indicator indicator-2"></div>
        <div class="dice-indicator indicator-3"></div>
        <div class="dice-indicator indicator-4"></div>
        <div class="dice-indicator indicator-5"></div>
        <div class="dice-indicator indicator-6"></div>
    </div>
</div>

samedi 10 mars 2012

Authentification SSL client avec Apache

Dans ce billet, nous allons voir comment sécuriser une application WEB afin qu'elle soit accessible uniquement à des terminaux autorisés. Pour cela, nous allons utiliser des certificats clients et faire en sorte que le serveur impose au client de lui présenter un certificat signé par une autorité de certification particulière.

Création des certificats

Création d'une autorité de certification

La première étape consiste à créer notre propre autorité de certification. Nous générons pour cela une clé RSA que nous stockons sous ca.key. A partir de cette clé, nous allons générer un certificat auto-signé. Grace aux commandes openssl ci dessous, nous obtenons les éléments suivants :
ca.key
La clé RSA de notre autorité de certification
ca.crt
Le certificat auto-signé de notre autorité
ca.public.key
La clé publique de notre autorité de certification
openssl genrsa -out ca.key
openssl req -new -key ./ca.key -out ./ca.csr
openssl x509 -req -days 365 -in ./ca.csr -out ./ca.crt -signkey ./ca.key
openssl x509 -in ca.crt -text
openssl rsa -in ca.key -passin pass:XXXX -pubout -out ca.public.key

Création et signature du certificat serveur

Il faut ensuite créer la clé et le certificat qui seront utilisé par le serveur. Le certificat serveur sera signé par notre propre autorité de certification créée à l'étape précédente. Lors de la création de la certificate signing request, il est demandé de renseigner un Distinguished Name (DN). La valeur de ce champ devra être identique à la valeur du ServerName utilisé dans le fichier de configuration Apache httpd.conf. En plus de la clé et du certificat, il peut être intéressant de générer une clé qui ne soit pas protégée par un mot de passe. Cela permet de ne pas avoir à saisir de mot de passe à chaque démarrage du serveur Apache.
openssl genrsa -des3 -out server.key
openssl req -new -key ./server.key -out server.csr
openssl x509 -req -in ./server.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out ./server.crt -days 365
openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12 -name "server certificate"
openssl pkcs12 -info -in server.p12
openssl rsa -in server.key -passin pass:XXXX -pubout -out server.public.key
openssl rsa -in server.key -out server.nopassphrase.key

Création et signature du certificat client

Nous allons maintenant créer de manière similaire un certificat client qui sera utiliser par le client pour s'authentifier auprès du serveur distant. Le certificat client sera signé par la même autorité de certification que le certificat du serveur.
openssl genrsa -des3 -out client.key
openssl req -new -key ./client.key -out client.csr
openssl x509 -req -in ./client.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out ./client.crt -days 365
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "client certificate"
openssl pkcs12 -info -in client.p12
openssl rsa -in client.key -passin pass:XXXX -pubout -out client.public.key

Configuration du serveur Apache

Il convient maintenant de configurer le serveur Apache que seuls les clients disposant d'un certificat signé par notre propre autorité de certification soient autorisés à se connecter. Dans le VirtualHost du port SSL par défaut, il suffit d'utiliser les directives suivantes :
# Doit correspondre au DN du certificat server
ServerName domain

# Encryption et certificat serveur
SSLEngine On
SSLCertificateFile conf/certs/server.crt
SSLCertificateKeyFile conf/certs/server.nopassphrase.key

# Impose la présentation d'un certificat client
SSLVerifyClient require
SSLVerifyDepth 2

# Certificat de l'autorité de certification reconnue pour les clients
SSLCACertificateFile conf/certs/ca.crt
SSLVerifyClient
La valeur require permet d'imposer au client la présentation d'un certificat X509 lors de la phase de négociation SSL.
SSLVerifyDepth
Indique le nombre maximum de niveau que le serveur va analyser pour décider s'il juge le certificat client acceptable. Une valeur de 0 permet de n'autoriser que les certificats clients auto-signés. Une valeur de 1 permet d'accepter les certificats clients auto-signés ou certifiés par une autorité de certification directement connue par le serveur. Dans notre cas, nous utilisons la valeur 2 afin de n'accepter que les certificats clients signés par une autorité de certification directement connue par le serveur.
SSLCACertificateFile
Cette directive permet de spécifier le certificat de l'autorité de certification reconnue par le serveur. Seuls les certificats clients signés par l'autorité de certification identifiée par ce certificat seront acceptés.
Dans un prochain article, nous verrons comment configurer un client Android pour accéder à ce serveur sécurisé.

dimanche 29 janvier 2012

Jersey custom parameter, annotation and exception mapping

Jersey is the JSR-311 reference implementation for JAX-RS (Java API for RESTful Web Services). One of the drawback of this API is its lack of documentation when you want to go deeper into some complex or recurrent issues. Because we all like KISS code, let see how to keep Jersey simple, stupid!

Let's take the following example where we want to :
  1. Map Java Exception to specific HTTP response with localized messages
  2. Inject parameters of any type with custom validation
  3. Define a specialized annotation for specific injectable parameters
A first shot with no optimization will look like this :
@Path("/test")
@Produces("application/json")
public class TestEndpoint {
    
    private static final Logger log = Logger.getLogger(TestEndpoint.class.getName());
    
    private static final ResourceBundle resource = 
        ResourceBundle.getBundle("com.blogspot.avianey");
    
    @Inject TestService service;
    
    @POST
    @Path("{pathParam: \\d+}")
    public String testMethod(
            @PathParam("pathParam") Long id,
            @FormParam("date") String dateStr,
            @Context HttpServletRequest request) {

        // verifying that the user is logged in
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            throw new WebApplicationException(Status.UNAUTHORIZED);
        }
        
        // verifying the format of the sent date
        Date date = null;
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException pe) {
            throw new WebApplicationException(Status.BAD_REQUEST);
        }
        
        try {
            // calling the business logic
            return service.testOperation(id, date, user);
        } catch (BusinessException boe) {
            log.log(Level.FINER, "Business problem while executing testMethod", boe);
            throw new WebApplicationException(
                    Response.status(Status.BAD_REQUEST)
                            .type(MediaType.TEXT_PLAIN)
                            .entity(resource.getString(boe.getMessage()))
                            .build());
        } catch (TechnicalException te) {
            log.log(Level.FINER, "Technical problem while executing testMethod", te);
            throw new WebApplicationException(
                    Response.status(Status.INTERNAL_SERVER_ERROR)
                            .type(MediaType.TEXT_PLAIN)
                            .entity(resource.getString("error.internal"))
                            .build());
        }
        
    }
    
}
It's easy to think about the number of duplicated lines of code we would have if such a solution is applied for all our exposed methods... Now it's time to go deeper into Jersey and JAX-RS.

Custom Exception mapping with Jersey

In a Three-Tier architecture, the Logic-Tier may throw an application specific BusinessException, the Data-Tier may throw a TechnicalException, and so on... As BusinessException are relative to business rule violations it might be interresting to alert the user with a comprehensive message in the Presentation-Tier. On the contrary, a synthetic message will be displayed to the user for TechnicalException that refers to problems that are not likely to happen.

Jersey makes it possible to bind Java Exception with specialized HTTP response. All we have to do is to register an ExceptionMapper for each Java Exception we want to handle in a generic manner.
@Provider
public class BusinessExceptionMapper implements ExceptionMapper<BusinessException> {

    private static final Logger log = Logger.getLogger(TestEndpoint.class.getName());
    
    private static final ResourceBundle resource = 
        ResourceBundle.getBundle("com.blogspot.avianey");

    @Override
    public Response toResponse(BusinessException e) {
        log.log(Level.FINER, "Business problem while executing testMethod", e);
        return Response.status(Status.BAD_REQUEST)
            .type(MediaType.TEXT_PLAIN)
            .entity(resource.getString(e.getMessage()))
            .build();
    }

}
@Provider
public class TechnicalExceptionMapper implements ExceptionMapper<TechnicalException> {

    private static final Logger log = Logger.getLogger(TestEndpoint.class.getName());
    
    private static final ResourceBundle resource = 
        ResourceBundle.getBundle("com.blogspot.avianey");

    @Override
    public Response toResponse(TechnicalException e) {
        log.log(Level.FINER, "Technical problem while executing testMethod", e);
        return Response.status(Status.INTERNAL_SERVER_ERROR)
            .type(MediaType.TEXT_PLAIN)
            .entity(resource.getString("error.internal"))
            .build();
    }

}
Just as service classes, @Provider classes should be placed in a package that is scanned by the Jersey Servlet at startup so they can be used at runtime.
<servlet>
    <servlet-name>Jersey</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>pkg.provider; pkg.endpoint</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
We no longer have to handle explicitly BusinessException and TechnicalException in our exposed method :
@Path("/test")
@Produces("application/json")
public class TestEndpoint {
    
    private static final Logger log = Logger.getLogger(TestEndpoint.class.getName());
    
    @Inject TestService service;
    
    @POST
    @Path("{pathParam: \\d+}")
    public String testMethod(
            @PathParam("pathParam") Long id,
            @FormParam("date") String dateStr,
            @Context HttpServletRequest request) {

        // verifying that the user is logged in
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            throw new WebApplicationException(Status.UNAUTHORIZED);
        }
        
        // verifying the format of the sent date
        Date date = null;
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException pe) {
            throw new WebApplicationException(Status.BAD_REQUEST);
        }
        
        // calling the business logic
        // no need to catch exception here anymore
        return service.testOperation(id, date, user);
        
    }
    
}

Custom Jersey parameters

JAX-RS Param annotations like QueryParam, FormParam and PathParam can be apply to any Java Object that have a constructor with a single String argument. When calling a method with such an annotated parameter, Jersey instantiate a new object with the param value and pass it to the method.

We can easily use this feature to centralize the validation of date parameters accross all of our exposed methods :
/**
 * A DateParam to validate the format of date parameters received by Jersey
 */
public class DateParam {

    private Date date;
    
    public DateParam(String dateStr) {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        try {
            this.date = sdf.parse(dateStr);
        } catch (ParseException pe) {
            throw new WebApplicationException(Status.BAD_REQUEST);
        }
    }
    
    public Date value() {
        return this.date;
    }
    
}
Once again, our original code gained in maintainability :
@Path("/test")
@Produces("application/json")
public class TestEndpoint {
    
    private static final Logger log = Logger.getLogger(TestEndpoint.class.getName());
    
    @Inject TestService service;
    
    @POST
    @Path("{pathParam: \\d+}")
    public String testMethod(
            @PathParam("pathParam") Long id,
            @FormParam("date") DateParam date,
            @Context HttpServletRequest request) {

        // verifying that the user is logged in
        User user = (User) request.getSession().getAttribute("user");
        if (user == null) {
            throw new WebApplicationException(Status.UNAUTHORIZED);
        }
        
        // calling the business logic
        return service.testOperation(id, date.value(), user);
        
    }
    
}

Contextual object injection

Now we will see how it possible to directly inject the logged User into our exposed method. There is two diferent approaches doing this :
  1. Use the @Context annotation with a custom provider to inject the desired Object
  2. Create a custom annotation and its Injectable and associated InjectableProvider
In the first approach, we define a new Injectable implementation for the User Type and associate it with the @Context annotation.
@Provider
public class LoggedUserProvider extends AbstractHttpContextInjectable<User>
        implements InjectableProvider<Context, Type> {

    private final HttpServletRequest r;
    
    public LoggedUserProvider(@Context HttpServletRequest r) {
        this.r = r;
    }

    /**
     * From interface InjectableProvider
     */
    @Override
    public Injectable<user> getInjectable(ComponentContext ic, Context a, Type c) {
        if (c.equals(User.class)) {
            return this;
        }
        return null;
    }

    /**
     * From interface InjectableProvider
     * A new Injectable is instanciated per request
     */
    @Override
    public ComponentScope getScope() {
        return ComponentScope.PerRequest;
    }

    /**
     * From interface Injectable
     * Get the logged User associated with the request
     * Or throw an Unauthorized HTTP status code
     */
    @Override
    public User getValue(HttpContext c) {
        final User user = Contestr.getSessionUser(r);
        if (user == null) {
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        }
        return user;
    }
}
The exposed method consist now of one line of code only !
@Path("/test")
@Produces("application/json")
public class TestEndpoint {
    
    @Inject TestService service;
    
    @POST
    @Path("{pathParam: \\d+}")
    public String testMethod(
            @PathParam("pathParam") Long id,
            @FormParam("date") DateParam date,
            @Context User user) {
        // calling the business logic
        return service.testOperation(id, date.value(), user);
    }
    
}
In the second approach, we need to define a new annotation :
@Target({ ElementType.PARAMETER, ElementType.METHOD, ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
public @interface LoggedUser {}
Just as seen before, we need to associate the @LoggedUser with a new Injectable for the User type :
@Provider
public class LoggedUserProvider  
    implements Injectable<User>, InjectableProvider<LoggedUser, Type> {

    private final HttpServletRequest r;
    
    public LoggedUserProvider(@Context HttpServletRequest r) {
        this.r = r;
    }

    @Override
    public Injectable<user> getInjectable(ComponentContext cc, LoggedUser a, Type c) {
        if (c.equals(User.class)) {
            return this;
        }
        return null;
    }

    /**
     * From interface InjectableProvider
     * A new Injectable is instanciated per request
     */
    @Override
    public ComponentScope getScope() {
        return ComponentScope.PerRequest;
    }

    /**
     * From interface Injectable
     * Get the logged User associated with the request
     * Or throw an Unauthorized HTTP status code
     */
    @Override
    public User getValue() {
        final User user = (User) r.getSession().getAttribute("user");
        if (user == null) {
            throw new WebApplicationException(Response.Status.UNAUTHORIZED);
        }
        return user;
    }
    
}
This solution is much more flexible than the previous one as we can build more than one annotation for the same Type :
  • @LoggedUser : retrieve the logged in User and throw an HTTP 401 unauthorized status code if no logged in User is associated with the current request.
  • @AdminLoggedUser : retrieve the logged in User and throw an HTTP 401 unauthorized status code if no logged in User is associated with the current request or if the User is not an administrator.
@Path("/test")
@Produces("application/json")
public class TestEndpoint {
    
    @Inject TestService service;
    
    @POST
    @Path("{pathParam: \\d+}")
    public String testMethod(
            @PathParam("pathParam") Long id,
            @FormParam("date") DateParam date,
            @LoggedUser User user) {
        // calling the business logic
        return service.testOperation(id, date.value(), user);
    }
    
}
In a next post, I will cover the integration of Jersey with Guice or any other JSR-330 compliant IOC framework.

dimanche 8 janvier 2012

Generic JPA sharded counter for Google App Engine

One of the drawback of The Google App Engine datastore is the rate at which it can handle update for a single entity or an entity group. The datastore documentation indicates that the maximum rates is arround 5 write operations per second for the same entity or entity group. To overpass this limitation, Google recommend to use horizontal partitioning by using sharded counter. The App Engine documentation provides a simple (an non transactional) JDO implementation of sharded counters. Let see how we can build an reusable and transactional JPA-based sharded counter for the Google App Engine.

The Counter Class

The Entity bellow allow us to implement sharded counters for almost anything :
count :
this attribute will handle the counter value for this sharded counter
refId :
the ID of the Entity this sharded counter is used for
entityClass :
the Entity class this sharded counter is used for
type :
what this counter is counting
@Entity
@SuppressWarnings("serial")
public class Counter implements Serializable {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Long count;
    private Long refId;
    private int type;
    private String entityClass;
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public Long getCount() {
        return count;
    }
    public void setCount(Long count) {
        this.count = count;
    }
    public Long getRefId() {
        return refId;
    }
    public void setRefId(Long refId) {
        this.refId = refId;
    }
    public String getEntityClass() {
        return entityClass;
    }
    public void setEntityClass(String entityClass) {
        this.entityClass = entityClass;
    }
    public int getType() {
        return type;
    }
    public void setType(int type) {
        this.type = type;
    }

}

The service and how to increment a counter

In order to increment the number of time a web page is viewed, we would like to do something like :
incrementCounter(WebPage.class, webPageId, WebPage.VIEWS)
Where webPageId is the id of the WebPage Entity and WebPage.VIEW a constant.

The incrementCounter method will work as follow :
  1. Defines a MAX_TRIES values to store the maximum number of time we will try to update an existing sharded counter
  2. Retrives the list of the sharded counter already persisted for the given type
  3. If none exists, a new sharded counter with a value of 1 is persisted for the given type, the method returns
  4. Else, one sharded counter is picked up at random and its value is incremented
  5. If the update fails, the number of remaining tries is decremented
  6. If there is no try left, a new sharded counter with a value of 1 is persisted for the given type, the method returns
  7. Else, start again at step 2
/**
 * Sum all the counter for the given type and entity
 * @param c
 * @param refId
 * @param type
 * @return
 */
protected long counterSum(Class<?> c, Long refId, int type) {
    long sum = 0;
    List<Counter> counters = getCounters(c, refId, type);
    for (Counter counter : counters) {
        sum += counter.getCount();
    }
    return sum;
}

/**
 * Get all the counter for the given type and entity
 * @param c
 * @param refId
 * @param type
 * @return
 */
private List<Counter> getCounters(Class<?> c, Long refId, int type) {
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("refId", refId);
    params.put("type", type);
    params.put("entityClass", c.getSimpleName());
    return list(Counter.class, 
        "SELECT c FROM Counter c WHERE refId = :refId AND type = :type AND entityClass = :entityClass", 
        params);
}

protected void incrementCounter(Class<?> c, Long refId, int type) {
    modifyCounter(c, refId, type, 1);
}

protected void decrementCounter(Class<?> c, Long refId, int type) {
    modifyCounter(c, refId, type, -1);
}

/**
 * Modify the counter value for the given type and entity
 * @param c
 * @param refId
 * @param type
 * @param step
 */
protected void modifyCounter(Class<?> c, Long refId, int type, int step) {
    int tries = MAX_TRIES;
    EntityManager em = getEntityManager();
    while (true) {
        try {
            List<Counter> counters = getCounters(c, refId, type);
            if (counters.size() == 0) {
                newCounter(c, refId, type, step);
                break;
            }
            try {
                em.getTransaction().begin();
                Random generator = new Random();
                int counterNum = generator.nextInt(counters.size());
                Counter counter = counters.get(counterNum);
                counter.setCount(counter.getCount() + step);
                em.merge(counter);
                em.getTransaction().commit();
                break;
            } finally {
                if (em != null) {
                    if (em.getTransaction().isActive()) {
                        em.getTransaction().rollback();
                    }
                }
            }
        } catch (ConcurrentModificationException cme) {
            if (--tries == 0) {
                newCounter(c, refId, type, step);
                break;
            }
        }
    }
}

private void newCounter(Class<?> c, Long refId, int type, int step) {
    EntityManager em = null;
    try {
        em = getEntityManager();
        Counter counter = new Counter();
        counter.setCount(Long.valueOf(step));
        counter.setEntityClass(c.getSimpleName());
        counter.setRefId(refId);
        counter.setType(type);
        em.getTransaction().begin();
        em.persist(counter);
        em.getTransaction().commit();
    } finally {
        if (em != null) {
            if (em.getTransaction().isActive()) {
                em.getTransaction().rollback();
            }
        }
    }
}


protected final <R> List<R> list(Class<R> c, String query, Map<String, Object> parameters) {
    EntityManager em = getEntityManager();
    Query select = em.createQuery(query);
    for (String key : parameters.keySet()) {
        select.setParameter(key, parameters.get(key));
    }
    List<R> list = select.getResultList();
    return list;
}
Enjoy!
Fork me on GitHub