jeudi 28 août 2008

Ganymede et maven

Pour utiliser Ganymede et maven, il est nécessaire d'utiliser la version 1.5 ou 2.0 de wtp :

mvn -Dwtpversion=1.5 eclipse:eclipse

Ou bien il est possible de le préciser dans le fichier settings.properties
<profile>
<id>dev</id>
<properties>
<wtpversion>2.0</wtpversion>
</properties>
</profile>

lundi 25 août 2008

Recommandation de codage JAVA

Utilisation des outils

Formatage du code

Sous eclipse :
Ctrl+Shift+F :
permet de formatter le code. Cette commande devrait être lancée avant le commit, de sorte à ce que quelqu'un qui passe cette commande soit toujours capable de reconstituer les changements qui se sont produits par l'historique.
Ctrl+Shift+O :
Supprime les imports inutiles

Checkstyle

Effectue une vérification du style d'un code. Un plugin checkstyle est utilisable sous eclipse il effectue parfois de bonnes suggestions, mais il est souvent un peu trop sévère. S'en inspirer seulement.

Programmation

Codage

Les noms de classe et d'interface

  • Un nom de classe doit éclairer sur sa fonction. Les noms comportant Handlers, utils et Manager sont à utiliser avec parcimonie, car il ne sont pas concret. Les éviter dans la mesure du possible, si toutefois le besoin était réel.
    • Handler est à utilisé pour effectuer des manipulations sur un objets.
    • Manager : conventionnellement un manager possède le pouvoir de création des objets qu'il manage (A la différence des handlers.)
    • Util : ne doit pas être utilisé pour désigner quelque chose d'utile (Normallement tout ce qui est programmé est utile), mais il doit désigner quelques chose de factorisable pour un groupe de classes (Le plus souvent ce sera le projet). Ce genre de chose s'applique par exemple au logs, au IO et chaque concept très général de l'informatique.
    • Helper : même si on le retrouve Helper et Util recouvrent la même utilisation. Il faut choisir l'un ou l'autre.
  • Les interfaces prennent le nom sans aucun suffixe, ni préfixe
  • Les implementations se trouvent dans des package différents que les interfaces.
  • Le rôle fonctionnel est à mettre avant la fonction technique :
    Exemple :
    AidaService est préferable à ServiceAida

Les méthodes

Le nom de la méthode doit donner une idée de ce qu'elle fait.
Elles commencent par un minuscule.
  • Ne pas utiliser les _ pour les noms de méthode
  • Séparer deux mots en utilisant une majuscule
  • Une méthode doit effectuer un traitement qui se rapporte à son nom (Ce nom ne doit pas être trop générique s'il n'existe pas d'interface qui impose ce nom)
  • Elle ne doivent pas être trop longue(moins de 60 lignes)

Noms des variables

  • Ne pas utiliser les _ pour les noms de variables.
  • La séparation de deux mots se fait à l'aide de majuscules.
  • Les noms de variables indiquent plutôt le contenu d'une variable plutôt que sa fonction technique.

Par exemple :
  1. Si une méthode retourne un dossier, n'est pas un bon nom "result" pour désigner le retour d'une méthode, il vaut mieux utiliser "dossier" comme nom de variable.
  2. list n'est pas parlant pour désigner une liste de dossier, il vaut mieux utiliser le nom "dossiers" Pour les ensemble d'objets de même nature, il suffit de mettre un s au nom de la variable.
  • Éviter les abréviations, elle nuisent toujours à la compréhension.

Documentation du code

La documentation du code est nécessaire surtout pour les méthodes qui effectuent des traitements qui ne sont pas descriptible par un simple nom de méthode.

Traitement conditionnel

Pour la clarté, il vaut mieux toujours mettre des crochets sur les block if et for.

Règles générale de programmation

Utilisation de l'abstraction

  • Contrairement à une idée reçue, il est plus simple de factoriser des classes effectuant des traitements similaires que de dé-factoriser des classes n'effectuant pas le même traitement. Concrètement, l'utilisation de abstraction n'est pas a priori meilleur pour la fiabilité d'un programme.
  • Les interfaces sont à utiliser dans le cas d'objets devant être manipulés sans qu'on en connaisse la nature précise.
  • Les classes abstraites, bien qu'elles puissent être utilisée dans un rôle d'interface, ne sont pas recommandable dans cette usage. Il faut les utiliser pour diminuer la taille d'une classe.
    • Elle sont suffixées par Base lorsqu'elle représente une base pour les autre classes.
    • Elle sont suffixées par Default lorsqu'il s'agit de prototypes, c'est à dire de classe non virtuelles
  • Quand on a recours massivement à des copier-coller d'une classe sur l'autre alors une classe abstraite peut être utile
  • Quand on a recours massivement à des copier-coller dans une même classe, alors il est bon de créer une méthode factorisant ces traitements

vendredi 8 août 2008

Debugging distant avec tomcat et eclipse

Dans setenv.sh rajouter la ligne :

export JAVA_OPTS="-Xmx1024M -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y"




Si vous souhaitez que le serveur ne démarre que s'il est connecté à éclipse.
Tapez :

export JAVA_OPTS="-Xmx1024M -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y"


Ensuite sur eclipse dans le menu debug

Choisissez

- Java Remote Application

Dans project choisissez le projet que vous voulez mettre en relation avec la tomcat, le source doit être celui qui a permis de générer votre application distante, sans quoi vous aurez des résultat incohérent.

Placez les breakpoints où vous le souhaitez, le remote debugging vous permettra de voir les variable, de placer des breakpoint etc. exactement comme dans un debbuging local.

mardi 5 août 2008

Howto crypt / uncrypt using JAVA and RSA keys

Problématique :

Dans le cadre d'un bus de données nous souhaitons sécuriser les données en transit. Comme il s'agit d'un bus de transfert asynchrone, lorsque des messages sont stockés sur les files JMS il doivent également être crypté pour n'apparaitre en clair qu'au consommateur. Il n'est pas possible de se servir de SSL puisque le cryptage ne concerne pas que les phase de transport.

Nous allons réaliser le cryptage au niveau des producteurs et consommateurs du bus en nous servant des fonctionnalités venant avec le JDK 5,0.

La principale limitation dans le cryptage JAVA vient de la profusion des différents formats. Pour ce faire nous allons nous servir d'un cryptage à partir de clé publique/clé privée.

La génération des fichiers clé privée et clé publique se fait à l'aide de openssh.


openssl genrsa -aes256 -out /public/cleprivee.pem 2048
openssl rsa -in /public/private.pem -pubout -outform DER -out clepublique.der
openssl pkcs8 -topk8 -inform PEM -in /public/cleprivee.pem -outform DER -nocrypt -out /public/cleprivee.pk8


Le format PK8 est le seul disponible nativement en JAVA, il sert pour la lecture des clés privées


Le format DER est supporté pour les clé publique en JAVA, il sert pour la lecture des clés publique.


Le code suivant crypte et décrypte un message « Mon Cul C'est du poulet » à partir d'une clé publique et privée lue sur dans des fichiers :




// Lecture du fichier de clé publique
File keyFile = new File("clepublique.der");
byte[] encodedKey = new byte[(int) keyFile.length()];
new FileInputStream(keyFile).read(encodedKey);
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey pk = kf.generatePublic(publicKeySpec);

// Encryptage à l'aide de la clé publique
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pk);
byte[] cypherText = cipher.doFinal("Mon Cul C'est du poulet"
.getBytes("UTF8"));

// Affichage du résultat du cryptage
System.out.println("----- Bytes cryptés --------");
System.out.write(cypherText);
System.out.println();
System.out.println("----------------------------");

// Lecture de la clé privée
keyFile = new File("cleprivee.pk8");
encodedKey = new byte[(int) keyFile.length()];
new FileInputStream(keyFile).read(encodedKey);
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
PrivateKey privateKey = (RSAPrivateKey) kf
.generatePrivate(privateKeySpec);
cipher.init(Cipher.DECRYPT_MODE, privateKey);

// Affichage du résultat décrypté
System.out.println("----- Bytes décryptés ------");
byte[] clearText = cipher.doFinal(cypherText);
System.out.write(clearText);
System.out.println();
System.out.println("----------------------------");



Ce code ne fonctionne pas quand les données sont trop longue car elle dépasse la taille de la clé. Dans ce cas pour des raison de performances, il vaut mieux utiliser des cryptage symétrique à l'aide de mot de passe. Le code qui suit en donne un illustration.

/** Le chiffreur */
Cipher cipher;

/** La cle de cryptage */
SecretKey secretKey;

public void init(String password) throws Exception {
cipher = Cipher.getInstance("DES");
keyFactory = SecretKeyFactory.getInstance("DES");
DESKeySpec privateKeySpec = new DESKeySpec(password.getBytes());
secretKey = keyFactory.generateSecret(privateKeySpec);
}

/**
* Crypte les données
*
* @return
* @throws Exception
*/

public byte[] encrypt(byte[] aCrypter) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayInputStream bais = new ByteArrayInputStream(aCrypter);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
CipherOutputStream cis = new CipherOutputStream(baos, cipher);
byte[] buffer = new byte[1024];
int read;
while ((read = bais.read(buffer)) != -1) {
byte[] buffer2 = cipher.update(buffer, 0, read);
baos.write(buffer2);
}
baos.write(cipher.doFinal());
buffer = baos.toByteArray();
return buffer;
}
/**
* Décrypte les données
*
*/

public byte[] decrypt(byte[] aDecripter) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayInputStream bais = new ByteArrayInputStream(aDecripter);
cipher.init(Cipher.DECRYPT_MODE, secretKey);

byte[] buffer = new byte[1024];
int read;
while ((read = bais.read(buffer)) != -1) {
byte[] buffer2 = cipher.update(buffer, 0, read);
baos.write(buffer2);
}
baos.write(cipher.doFinal());
buffer = baos.toByteArray();
return buffer;
}

lundi 30 juin 2008

Projets EMF

EMF est un métamodèle qui permet de décrire ses données à travers des éditeur.
Associé à open Architecture, il permettra de faire de la génération de code et sera utile pour générer massivement des services ou des bean (Par exemple si l'on souhaite rendre accessible une référentiel depuis l'extérieur).

Cette solution souffre principalement d'une complexité importante. Une vingtaine de jours environ et nécessaire pour se familiariser avec le produit.
En dépit de cet incontestable défaut EMC c'est une solution de métamodèle qui pourra remplacer avantageusement les outils traditionnel de modélisation dans les entreprise où Eclipse est au centre des développements. Il peu même se substituer à Power AMC ou Pational Rose dans les cas où le développements sont fortement couplés avec la modélisation.

Le premier pas pour se familiariser avec EMF est de suivre le tutorial.

vendredi 27 juin 2008

Sécuriser un service Axis2 avec des certificats

Pour sécuriser un service par une authentification basé sur certificat.


Il faut d'abord créer les magasin de clés pour le serveur et le client. Ces clés serviront pour authentifier les partis.

Ensuite, le serveur fournit un certificat pour le client, il faut considérer ce certificat comme une autorisation de se connecter au serveur (C'est pour cette raison qu'elle doit provenir du serveur). Ensuite, le client l'importe dans son magasin. Ces commandes se passent à laide de keytool.


keytool -genkey -alias serverkey -keystore keystoreserver.jks
keytool -genkey -alias clientkey -keystore keystoreclient.jks
keytool -selfcert -alias serverkey -keystore keystoreserver.jks
keytool -export -alias serverkey -keystore keystoreserver.jks>moncertif
keytool -printcert -file moncertif
keytool -import -keystore keystoreclient.jks -file moncertif


Il ne reste plus qu'à configurer axis2. Copier d'abord, le magasin de clé (keystore du serveur dans le répertoire classes/ de Axis2). Puis, dans le fichier conf/axis2.xml. Modifier les receiver et sender. Dans notre configuration le truststore est confondu avec le keystore. Si le besoin existait de les séparer le truststore doit contenir le certificat importé et le keystore, la clé de signature du serveur.


  <transportReceiver name="https" class="org.apache.axis2.transport.nhttp.HttpCoreNIOSSLListener">
<parameter name="port" locked="false">9002</parameter>
<parameter name="non-blocking" locked="false">true</parameter>
<parameter name="keystore" locked="false">
<KeyStore>
<Location>keystoreserver.jks</Location>
<Type>JKS</Type>
<Password>axis2rules</Password>
<KeyPassword>axis2rules</KeyPassword>
</KeyStore>
</parameter>
<!--parameter name="truststore" locked="false">
<TrustStore>
<Location>keystoreserver.jks</Location>
<Type>JKS</Type>
<Password>axis2rules</Password>
</TrustStore>
</parameter-->
<!--<parameter name="SSLVerifyClient">require</parameter>
supports optional|require or defaults to none -->
</transportReceiver>



    <transportSender name="https" class="org.apache.axis2.transport.nhttp.HttpCoreNIOSSLSender">
<parameter name="non-blocking" locked="false">true</parameter>
<parameter name="keystore" locked="false">
<KeyStore>
<Location>keystoreserver.jks</Location>
<Type>JKS</Type>
<Password>axis2rules</Password>
<KeyPassword>axis2rules</KeyPassword>
</KeyStore>
</parameter>
<parameter name="truststore" locked="false">
<TrustStore>
<Location>keystoreserver.jks</Location>
<Type>JKS</Type>
<Password>axis2rules</Password>
</TrustStore>
</parameter>
<!--<parameter name="HostnameVerifier">DefaultAndLocalhost</parameter>
supports Strict|AllowAll|DefaultAndLocalhost or the default if none specified -->
</transportSender>



Enfin, il faut en fait rajouter deux lignes dans le code client :

System.setProperty("javax.net.ssl.trustStore", "chemin au clientTruststore");
System.setProperty("javax.net.ssl.trustStorePassword", "mot de passe du clientTruststore");

Pourquoi utiliser Spring dans un Web Service ?

Spring est un framework d'injection, et pour comprendre son intérêt il faut comprendre ce mécanisme et son intérêt.

L'injection est l'affectation d'une propriété par une sorte de container light(C'est le rôle de Spring). Dans le cadre d'une application simple (C'est à dire standalone) l'injection s'identifie simplement à une forme d'utilisation de pattern singleton.

On se sert de l'injection pour principalement deux cas de figure :

- Configurer et dimensionner par un bean de Configuration.
- Contrôler strictement ses instanciations pour pouvoir dimensionner précisément (Utiliser une seule instance DAO pour l'ensemble de ses instance de service par exemple).

Dans le cadre général des serveurs d'application, la notion d'injection est plus complexe. Il faut avant tout de comprendre qu'elle est liée au classloader et qu'il se pose des problème de scope. Ainsi, ce n'est pas parce qu'on injecte une propriété dans l'application, que cette propriété est injectée dans l'ensemble des instances de services.

Dans le cas des Web-Service, l'utilisation de Spring n'est donc pas triviale. Pour faire court, sil vous utiliser Axis et que vous souhaiter utiliser Spring dans axis, c'est un peu comme de vouloir utiliser deux moteur de Web-Service en un.

Même si cela reste possible, dans la majeur partie des cas il vaut mieux : soit se servir de httpinvoker (inclus dans spring).
Ou bien, si la fonction de container de Web-Service est fondamentale, ne se servir que du conteneur et ne pas utiliser Spring, cela est vrai pour : Axis, Axis2 etc.