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;
}