dimanche 29 janvier 2012

Gestion d'un projet complexe avec Maven - 1ère partie les librairies

Le but de cet article n'est pas de présenter Maven une fois de plus mais de proposer une solution correcte pour la gestion d'un projet diviser en plusieurs modules.

Gestion des librairies

Pour réaliser votre projet, vous allez certainement écrire une série de librairies. Certaines de ces librairies vont dépendre de librairies écritées également dans le cadre de ce projet.
Lors de la mise en production vous voulez bien évidemment suivre les bonnes pratique en faisant des releases de vos librairies et de vos modules. Tout ce petit monde se retrouvera alors en version 1.0.0
La mise en production s'est bien passée et le lendemain vous décellez un problème dans une de vos librairies : common-mail qui vous permet de gérer les mails multi-langues. Vous vous empressez de corriger le bug, vous testez votre application (tests unitaires, test fonctionnels) puis vous faire une release. Votre librairie se retrouve donc en version 1.0.1
Les mois / années passent toutes vos librairies ont changé de version; vous avez bossé sur d'autres projets et on vous demande de corriger un bug dans votre application. Là se pose la grandes série de questions, quelle librairie je peux utiliser à sa dernière version, quelle librairie je dois laisser à telle version, les versions sont elles compatibles entre elles ?
N'étant pas nés de la dernière pluie vous aviez prévu le coup au début du projet en vous disant que vous tiendrez un fichier à jour des différentes versions. Mais des mises en productions dans l'urgence on mit à mal votre idée.
On s'aperçoit qu'il y a un soucis d'organisation. Pour éviter ce problème, le plus simple est de gérer toutes les librairies avec le même numéro de version.
Le plus simple pour cela est de créer un module maven.
Faites un premier pom.xml
<groupId>superloutre.common<groupId>
<artifactId>common-parent</artifactId>
<version>1.0.0-SNAPSHOT<version>

Dans lequel vous déclarez toutes vos librairies

<modules>
<module>common-mail</module>
<module>common-toolbox</module>
<module>common-sales</module>
</modules>


Dans le répertoire du fichier pom.xml il faut maintenant créer chacun de ces répertoires où vous y mettrez la librairie correspondante.

De cette manière lorsque vous effectuerez des releases pour toutes vos librairies qui auront toujours la même version.

Gestion des versions des libraries et framework utilisés

Un beau projet tout neuf a donc commencé, vous avez décidé d'utiliser le couple gagnant Spring / Hibernate le tout agrémenté de quelques librairies apache et autres.

Vous avez donc ajouté cette dépendence dans quelques une de votre librairies et applications

<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.0.5.RELEASE</version>

On vous apprend qu'une faille de sécurité / bug a été détecté, il faut passer à la version 3.0.6.RELEASE.
Et là commence la galère. Mais vous vous êtes un vrai, vous êtes sous linux et maîtrisez grep, sed, et autres. Avec la ligne de commande de la mort qui tue vous passez tous vos projets à la bonne version de Spring. Vous buildez le projet tout se passe bien, vous lancez et hop vous vous chopez une erreur du genre class a.b.c.xxx is not an instance of a.b.c.xxx Vous allez vérifier les dépendences et vous vous apercevez que vous avez oublié de mettre à jour les version de spring-core.
Ne l'oublions pas, vous êtes un vrai, comme on dit par chez nous "keee problêêmm". Vous faites un grep "org.spring" Build avec tests unitaires, "alles an de rei" ("Tout est en ordre" pour ceux qui ne maîtrisent pas la langue du Grand Duc)
Vous buildez votre application web et là paf le chien, la version de la librairie de Spring webflow n'existe pas. Une p'tite recherche et vous vous apercevez que Spring Webflow n'est pas à la même version.

<groupId>org.springframework.webflow</groupId>
<artifactId>spring-webflow</artifactId>
<version>2.3.0.RELEASE</version>
Clairement c'est le bazar. SVN/GIT Rollback des pom, vous devez tout reprendre.
Pour palier à ce genre de problème on peut utiliser des variables que l'on déclare dans les poms
<org.springframework.version>3.0.5.RELEASE<org.springframework.version>
<org.springframework.webflow.version>2.3.0.RELEASE<org.springframework.webflow.version>

Il suffit alors de remplacer la version de la dépendance.

<groupId>org.springframework.webflow</groupId>
<artifactId> spring-webflow</artifactId>
<version>${org.springframework.webflow.version}</version>

Avec cette solution vous n'avez plus qu'à chercher
<org.springframework.version>3.0.5.RELEASE<org.springframework.version> dans vos projets.

Mais il y a encore plus simple.
Avec votre joli module maven, il vous suffit de déclarer les versions dans le pom common-parent et d'ajouter le code suivant dans les modules.
<parent>
<groupId>superloutre.common</groupId>
<artifactId>common-parent</artifactId>
<
version>1.0.0-SNAPSHOT</version>
</parent>

Vous n'aurez alors plus qu'à modifier les versions des librairies à un seul endroit.


Plugin maven utilisés

Afin d'éviter tout comportement hasardeux, il est vivement recommandé de spécifier les différents plugin maven utilisés pour le build.
La plupart peuvent être déclarés dans common-parent. Si le comportement est toujours le même.
Il en est de même pour les sections telles que distribution management.
Essayez toujours de mettre les informations si possibles dans le pom parent.
Attention à ne pas forcement faire cela pour les dépendances, sinon vous risquez d'embarquer des librairies non nécessaires à la compilation de chacune de vos librairies.


A suivre :
2ème partie : Gestion des modules de votre application
3ème partie : Où l'on parle du versionning de la base de données
4ème partie : Intégration continue, Versionning
5ème partie : Déploiement par RPM
6ème partie : Code source d'exemple
7ème partie : Pour aller plus loin

jeudi 26 novembre 2009

Création load balancer

Version brute à commenter

load balancer

Installation des outils pour la gestion d'un load balancer
yum install ipvsadm
modprobe iptable_mangle
modprobe iptable_filter

On ignore les requetes arp de localhost

cat
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
>> /etc/sysctl.conf

sysctl -p

cat -A -f 1 -s wrr -p 1800
-a -f 1 -r 192.168.248.100:0 -g -w 1
-a -f 1 -r 192.168.248.249:0 -g -w 1
>> /etc/sysconfig/ipvsadm

/etc/init.d/ipvsadm reload

iptables -t mangle -I PREROUTING 1 -j CONNMARK --restore-mark
iptables -t mangle -A PREROUTING -d 192.168.248.13 -p tcp --dport 38080 -j CONNMARK --save-mark
iptables -t mangle -A PREROUTING -d 192.168.248.13 -p tcp --dport 38080 -j MARK --set-mark 0x1
/etc/init.d/iptables save
/etc/init.d/iptables restart

serveurs destinations

cat net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
>> /etc/sysctl.conf

sysctl -p

ifconfig lo:0 192.168.248.13 netmask 255.255.255.255

administration
list :
ipvsadm -L -n
desactivate :
ipvsadm -d -r 192.168.248.100:0 -f 1
restore :
ipvsadm -a -r 192.168.248.100:0 -f 1 -g -w 1

mardi 26 mai 2009

Java : Gestion des listes; généricité et problème d'héritage

Voici la description d'un problème simple concernant les génériques en Java.
Dans une classe commande qui permet de gérer la commande d'un client dans un site marchand, nous devons y stocker la liste des lignes de commandes (OrderLines).
Devant gérer plusieurs types de lignes de commandes en fonction des produits commandés : Téléphone (géré par la classe ObjectOrderLine), abonnement (géré par la classe SubscriptionOrderLine)

Notre classe commande ressemblera donc à cela
class Order {

private long id;

private User user;

private List orderLines;

...
}

Le client commande une liste d'objet & accessoires
List orderedObjects = new ArrayList ();

Il ne sera pas possible de faire
order.getOrderLines.addAll(orderedObjects);

En effet, le compilateur s'attend à avoir une liste d'objet du type OrderLine et non pas une de ses sous classes.

Dans ce cas, il suffit d'utiliser les wildcards pour s'en sortir aisement.
class Order {
private List orderLines;

}