lundi 29 octobre 2012

L’encapsulation ne résiste pas à l’introspection


L’introspection Java, basée sur la « Java Reflexion API »,  permet de découvrir la structure de n’importe quelle classe. Ce principe permet donc de connaitre tous les éléments constitutifs d’une classe (champs, constructeurs, méthodes, ...) et d'agir sur ces éléments. Tous développeurs Java connaissent les usages classiques de cette API, mais si vous lisez cet article jusqu'à la fin vous verrez qu'une utilisation poussée de l'introspection permet d'aller extrêmement loin, par exemple jusqu'à modifier la valeur de la constante "TRUE" de la classe "Boolean" !   Etonnant, non ?

Utilisation basique de l'introspection 

Un des principaux intérêts de la réflexion est de pouvoir récupérer dynamiquement les valeurs des champs et d’invoquer les méthodes d’un objet dont on ne sait rien et sans avoir besoin du code source. Ce qui permet aux frameworks et autres bibliothèques Java en tous genres de récupérer des informations à partir, par exemple, d’un nom symbolique.

Ainsi,  avec l’ Expression Language dans les JSP l’expression « ${employe.nom} » sera analysée, puis la méthode « getNom() » de l’objet nommé « employe » sera invoquée et le résultat inséré à la place de l’expression.

Donc l’introspection c’est pratique, c’est même indispensable et jusque là tout va bien…
Mais l’introspection ne se limite pas à la consultation des objets, il est également possible de changer la valeur des champs et d’invoquer des méthodes qui modifient les données d’un objet (typiquement en invoquant des « setters »).

Alors qu’en est-il  de la sécurité ? 

Par défaut, les principes de sécurité qui sont appliqués à l’introspection sont les mêmes que ceux qui régissent les droits d’accès aux champs et aux méthodes d’un objet quand on utilise une classe lors du développement.

Donc  les méthodes et les champs privés d’une classe ne sont pas accessibles.

Exemple 1 – Tentative de modification d'un champ « private »  :
Field field = null ;
try {
   field = Employee.class.getDeclaredField("salary"); // Champ "private"
} catch (SecurityException e) {
   e.printStackTrace();
} catch (NoSuchFieldException e) {
   e.printStackTrace();
}

try {
   field.setDouble(employee, 1234.56); // Tentative de modification
} catch (IllegalArgumentException e) {
   e.printStackTrace();
} catch (IllegalAccessException e) {
   e.printStackTrace();
}


L'exécution de ce code va provoquer une Exception :
IllegalAccessException : Class .... can not access a member of class .... with modifiers "private"
puisque le champ "salary" est "private"


Comment les frameworks font-ils pour valoriser des champs privés ?

Les ORM (JPA, Hibernate, etc.. )  réussissent pourtant à valoriser des champs privés après un accès à la base de données
public class Employee {
   @Id
   @Column(name="EMP_ID")
   private int id; // Champ valorisé par JPA
   @Column(name="NAME")
   private String name; // Champ valorisé par JPA
}

Et c’est la même chose pour l’injection de dépendance…
public MyClass {
   @Inject
   private MyResource resource; // Injection (affectation d'une instance)
}

Il y a évidemment une solution :  il suffit d’appeler la méthode
« setAccessible(true) » sur le champ concerné pour le déverrouiller et le rendre immédiatement accessible, c'est-à-dire modifiable.


Exemple 2 - utilisation de setAccessible :
field.setAccessible(true);
field.setDouble(employee, 1234.56); // Et la tout se passe bien

L’appel  à  « setAccessible() » supprime les contrôles d’accès aux champs, méthodes et constructeurs (méthode héritée de la classe AccessibleObject)



L’utilisation de « setAccessible() »  est soumise à l’autorisation du « SecurityManager »
(cf java.lang.SecurityManager), un objet qui définit la politique de sécurité d’une application.

Pour obtenir le SecurityManager s’il existe :
SecurityManager secManager = System.getSecurityManager() ;
Dans certains environnements particuliers un SecurityManager peut être présent, notamment pour tout ce qui concerne le code téléchargé (Applets, Java Web Start, etc… ).  Mais par défaut la JVM n’a pas de SecurityManager, ce qui permet notamment d’utiliser JPA et l’injection de dépendance sans aucun problème dans pratiquement tous les cas.


Et si le champ est « final » ?

En principe un champ « final » n’est pas modifiable à postériori… Mais avec la « reflexion API » c’est possible, modifier un champ « private final » se fait exactement comme pour un champ « private »
non « final »

Et si le champ est « final static » ?

Alors là ça change tout !
Il s’agit d’un champ porté par la classe et qui sert de constante, donc  la « reflexion API » a quelques scrupules à nous laisser le modifier à tout moment. Et donc, même avec un appel préalable à  « setAccessible(true) » une exception sera levée :
IllegalAccessException: Can not set static final …. field …. to … 
Et on se dit que c’est tant mieux, car ce serait un peut cavalier de modifier des constantes…

Hummm….  Pourtant en poussant la réflexion (c’est le cas de le dire) un peu plus loin on arrive à la conclusion suivante : c’est le « final » qui pose problème quand il s’applique à un champ « static ».
Et qu’est-ce qui matérialise cette caractéristique « final » ? C’est un des « modifiers » récupérable avec « getModifiers() ».

Exemple 3 - utilisation des "modifiers" :
int fieldModifiers = field.getModifiers(); 
if ( Modifier.isStatic(fieldModifiers) ) {
   if ( Modifier.isFinal(fieldModifiers) ) {
      // static et final
   }
}

Donc, si on supprime le « modifier »  « final » ça va passer ?   He bien  oui !

Ce qui veut dire qu’un champ qui était « private » peut devenir « public » ou perdre sa
caractéristique  « final » ?
Et oui, en effet…   Il suffit de modifier les « modifiers » du champ.

Comment modifier les « modifiers » d’un champ ?

Les « modifiers » sont stockés dans un champ « private » de type « int » de la classe « Field », il faut donc s’attaquer directement à cette classe ( Field ) pour rendre ce champ accessible et donc de  pouvoir ensuite le modifier.
On va donc introspecter et modifier les classes qui servent à l'introspection (oui, on pousse le bouchon un peu loin, mais on s'arrêtera là,  promis...).

Le principe est le suivant :
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true); // "modifiers" est maintenant modifiable
Une fois accessible, il suffit d’affecter la nouvelle combinaison de « modifiers » à ce champ
modifiersField.setInt(targetField, newModifiers ) ;
( des exemples complets sont fournis un peu plus loin )

Comment l’introspection remet en cause l’immuabilité des objets

En Java un attribut est immuable s’il est « private » et que la classe ne fournit aucune méthode permettant de le modifier.
Ainsi, depuis les premiers cours d’initiation à Java on nous a expliqué que les instances de « Boolean » et « String » par exemple étaient immuables. Et pourtant, en poussant l’introspection dans ses derniers retranchements il est tout à fait possible de modifier de type d’objets (voir les exemples ci-après)

Voici quelques exemples d’utilisation un peu « border line » de l’introspection qui démontrent qu'on peut aller très loin (trop loin ?)...

NB : Ces exemples sont potentiellement dangereux et n'ont pas vocation à être utilisés dans une application réelle.


Exemple A  – Modifier le contenu d’une instance de la classe "Boolean"

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * Modification d'une instance de Boolean avec la Reflexion API
 * Copyright (c) 2012 Laurent Guerin - Licence LGPL v3
 */
public class ChangeBoolean {

 public static void main(String[] args) {
  
  Boolean b1 = new Boolean(true) ;
  
  System.out.println(" b1  : " + b1 + ", b1.booleanValue() : " + b1.booleanValue() );
  
  try {
   changeValue( b1, false ) ;
  } catch (Exception e) {
   e.printStackTrace();
  }
  
  System.out.println(" b1  : " + b1 + ", b1.booleanValue() : " + b1.booleanValue() );  
 }

 /**
  * Change la valeur d'un booleen
  * @param instance du booleen a modifier 
  * @param newValue valeur a affecter
  * @throws Exception
  */
 public static void changeValue(Boolean instance, boolean newValue) throws Exception {

  // La valeur est portee par le champ "value" de la classe "Boolean"
  Field field = Boolean.class.getDeclaredField("value") ;
   
  int targetFieldModifiers = field.getModifiers();
  if ( Modifier.isFinal(targetFieldModifiers) ) System.out.println(" field is 'final' ");
  if ( Modifier.isPrivate(targetFieldModifiers) ) System.out.println(" field is 'private' ");
  // Le champ "value" est "final" et "private"
  
  field.setAccessible(true) ;

  System.out.println(" original value : " + field.get(instance) );
  System.out.println(" change value to : " + newValue);
  field.set(instance, newValue) ;
 }
}

Exemple B  – Modifier le contenu d’une instance de la classe "String"

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * Modification d'une instance de String avec la Reflexion API
 * Copyright (c) 2012 Laurent Guerin - Licence LGPL v3
 */
public class ChangeString {

 public static void main(String[] args) {
  
  String s = "Hello world !" ;
  String s2 = new String(s) ;
  
  System.out.println("s = " + s  + " s.hashCode = " + s.hashCode());
  System.out.println("s2 = " + s  + " s2.hashCode = " + s2.hashCode());
  System.out.println("s == s2 ?  " + ( s == s2 ) );
  System.out.println("s.equals(s2) ?  " + ( s.equals(s2) ) );
  
  try {
   System.out.println("Convert to uppercase...");
   toUpperCase( s ) ;
   System.out.println("s  = " + s  + " hashCode = " + s.hashCode());
   
   System.out.println("Change value ...");
   populate(s, "ABCDEFGHIJ") ;
   System.out.println("s = " + s  );
   
  } catch (Exception e) {
   e.printStackTrace();
  }
  
  System.out.println("s  = " + s  + " s.hashCode = " + s.hashCode());
  System.out.println("s2 = " + s2  + " s2.hashCode = " + s2.hashCode());
  System.out.println("s.equals(s2) ?  " + ( s.equals(s2) ) );
  System.out.println("s.equals('ABCDEFGHIJ') ?  " + ( s.equals("ABCDEFGHIJ") ) );
 }

 /**
  * Converti la chaine en majuscules
  * @param s 
  * @throws Exception
  */
 public static void toUpperCase ( String s ) throws Exception {

  // Les caracteres qui composent une String sont dans le champ "value" (private)  
  // qui pointe sur un tableaux de "char" 
  Field valueField = String.class.getDeclaredField("value");
  // Hash code de la chaine 
  Field hashField   = String.class.getDeclaredField("hash"); 
   
  int targetFieldModifiers = valueField.getModifiers();
  if ( Modifier.isFinal(targetFieldModifiers) ) System.out.println(" field is 'final' ");
  if ( Modifier.isPrivate(targetFieldModifiers) ) System.out.println(" field is 'private' ");
  
  valueField.setAccessible(true) ; 
  hashField.setAccessible(true) ;

  String sUpperCase = s.toUpperCase() ;
  char[] newValue = sUpperCase.toCharArray(); // Same array size => no pb

  valueField.set(s, newValue ); 
  hashField.setInt(s, newValue.hashCode()); // Hash code
  // La conversion en majuscules conserve le meme nombre de caracteres 
  // il n'y a donc rien d'autre a changer
 }
 
 /**
  * Change la valeur d'une chaine
  * @param s chaine a modifier
  * @param newString chaine a affecter
  * @throws Exception
  */
 public static void populate ( String s, String newString ) throws Exception {
  // Caracteres de la chaine
  Field valueField  = String.class.getDeclaredField("value");
  // Offset sur le tableau de char
  Field offsetField = String.class.getDeclaredField("offset");
  // Nombre de caracteres dans le tableau
  Field countField  = String.class.getDeclaredField("count");
  // Hash code de la chaine 
  Field hashField   = String.class.getDeclaredField("hash"); 
  
  valueField.setAccessible(true) ;
  offsetField.setAccessible(true) ;
  countField.setAccessible(true) ;
  hashField.setAccessible(true) ;

  // Affichage des valeurs d'origine 
  char[] value = (char[]) valueField.get(s);
  String sValue = new String(value);
  System.out.println("value  = '" + sValue + "' ( length = " + value.length + ", hashCode = " + s.hashCode() + " )" );
  System.out.println("offset = " + offsetField.getInt(s) );
  System.out.println("count  = " + countField.getInt(s) );
  System.out.println("hash   = " + hashField.getInt(s) );

  // Nouvelle chaine a affecter 
  String newValue = newString ;
  valueField.set(s, newValue.toCharArray() );
  // Le nombre de caracteres change => mettre a jour les autres informations 
  offsetField.setInt(s, 0); // Offset : on demarre a 0
  countField.setInt(s, newValue.length()); // Nombre de caracteres
  hashField.setInt(s, newValue.hashCode()); // Hash code  
 }
}


Exemple C  – Modifier la valeur de la constante "TRUE" de la classe "Boolean"
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * Modification d'une constante de la classe Boolean avec la Reflexion API
 * Copyright (c) 2012 Laurent Guerin - Licence LGPL v3
 */
public class ChangeBooleanTRUE {

 public static void main(String[] args) {
  System.out.println("=== AVANT : ");
  System.out.println(" Boolean.TRUE  : " + Boolean.TRUE  );
  System.out.println(" Boolean.FALSE : " + Boolean.FALSE );
  System.out.println(" Boolean.valueOf(true)  : " + Boolean.valueOf(true)  );
  System.out.println(" Boolean.valueOf(false) : " + Boolean.valueOf(false) );
  
  try {
   changeTRUEConstant( false ) ;
  } catch (Exception e) {
   e.printStackTrace();
  }
  
  System.out.println("=== APRES : ");
  System.out.println(" Boolean.TRUE  : " + Boolean.TRUE  ); // false (!)
  System.out.println(" Boolean.FALSE : " + Boolean.FALSE );
  System.out.println(" Boolean.valueOf(true)  : " + Boolean.valueOf(true)  ); // false (!)
  System.out.println(" Boolean.valueOf(false) : " + Boolean.valueOf(false) );
 }

 
 /**
  * Change la valeur de la constante TRUE (!) 
  * @param newValue
  * @throws Exception
  */
 public static void changeTRUEConstant( boolean newValue ) throws Exception {

  // La constante TRUE ( final static ) 
  Field field = Boolean.class.getDeclaredField("TRUE") ;
  
  field.setAccessible(true) ;
  
  int fieldModifiers = field.getModifiers();
  
  if ( Modifier.isStatic(fieldModifiers) ) {
   if ( Modifier.isFinal(fieldModifiers) ) {
    // Ce champ est "final static" : il faut supprimer "final"
    removeFinalModifier(field);
   }
  }
  // Affectation de la nouvelle valeur 
  field.set(null, newValue) ;
 }
 
 /**
  * Supprime le modifier "final" du champ 
  * @param targetField
  * @throws Exception
  */
 public static void removeFinalModifier(Field targetField) throws Exception {

  Field modifiersField = Field.class.getDeclaredField("modifiers");
  
  modifiersField.setAccessible(true); // Les "modifiers" sont maintenant accessibles

  int targetFieldModifiers = targetField.getModifiers();
  
  modifiersField.setInt(targetField, targetFieldModifiers & ( ~Modifier.FINAL ) ) ; // Le champ n'est plus "final"
  
 }
}

Conclusion :  introspection = no limit !

En  conclusion, avec la « Java Reflexion API »  on peut pratiquement tout modifier dynamiquement, y compris des données réputées immuables. Ce qui ouvre des perspectives intéressantes mais potentiellement dangereuses. L’introspection est donc un outil puissant, mais à manipuler avec précaution.



samedi 6 octobre 2012

Coloration syntaxique de code avec SyntaxHighlighter 3 dans Blogger

Tous les "développeurs-bloggers" ont besoin d'afficher des extraits de code de leur langage préféré.
Et du code avec coloration syntaxique c'est tout de suite beaucoup plus sympa pour les lecteurs.

N'échappant pas à la règle, j'entreprends aujourd'hui d'utiliser le célèbre SyntaxHighlighter (v3) d'Alex Gorbatchev (http://alexgorbatchev.com/SyntaxHighlighter/) dans Blogger. Et comme ça peut être utile à d'autres développeurs, voici la marche à suivre étape par étape...

1) A savoir

SyntaxHighlighter est uniquement constitué de styles CSS et de JavaScript (le petit bout de Flash a été supprimé dans la version 3). Il suffit donc d'insérer les tags qui font référence aux différents fichiers CSS et JS au bon endroit et le tour est joué.
Dans Blogger l'endroit en question c'est le "Template" (ou "Modèle") du blog.

2) Faire une sauvegarde du template

On ne sait jamais... Il vaut mieux être prudent
  • Aller sur la page d'administration du blog
  • Sélectionner "Modèle"
  • puis "Sauvegarde/Restauration" 
  • et "Télécharger le modèle complet"
Il s'agit d'un fichier XML avec un nom du genre "template-xxxx.xml" qu'on gardera au chaud sur le disque du poste de travail (au cas où)...

3) Modifier le "Template" ( ou "Modèle" en français )
  • Cliquer sur "Modifier le code HTML"
  • Un message d'avertissement s'affiche mettant en garde sur les conséquences possibles de cette modification, considérant qu'on sait ce qu'on fait il n'y a plus qu'à cliquer sur "Traiter"
  • Le code HTML s'affiche (avec la structure d'un page HTML standard)
  • Il suffit d'insérer le code ci-dessous juste avant le tag fermant   </head>  
    (ce bloc de code contient uniquement les fichiers "shBrushXxx.js" pour les langages les plus courants, il en existe d'autres sur le site de référence)
<!-- Syntax Highlighter 3.0.83 START -->
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shCore.css' rel='stylesheet' type='text/css'/>
<link href='http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css' rel='stylesheet' type='text/css'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushBash.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCss.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPerl.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushPhp.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js' type='text/javascript'/>
<script src='http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js' type='text/javascript'/>
<script language='javascript' type='text/javascript'>
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.all();
</script>
<!-- Syntax Highlighter 3.0.83 END -->
  • Enregistrer le modèle
  • "Fermer"
  • Afficher le blog
Si tout c'est bien passé le blog doit s'afficher normalement (aucune différence)
Pour vérifier que l'ajout a bien été pris en compte par Blogger afficher le code source de la page (qui doit contenir notre ajout)

Avec certains navigateurs (dont Google Chrome) la colonne qui affiche le numéro de ligne ne contient qu'un seul caractère et provoque l'affichage de lignes vides.
Pour corriger ce problème ajouter le code suivant :
<style>
    .syntaxhighlighter table td.gutter .line {
       padding: 0 !important;
    }
</style>

Blogger est maintenant prêt à accueillir du code qui sera colorisé en fonction du type de langage.

4) Utilisation 

L'incrustation de code peut se faire de deux façons ( avec les tags <pre> ou <script> )

<pre class="brush: js">
Les lignes de code

</pre>


<script type="syntaxhighlighter" class="brush: js"><![CDATA[
  Lignes de code
]]></script>

"brush" désigne la nature du langage.

Pour plus de détails : http://alexgorbatchev.com/SyntaxHighlighter/manual/installation.html

Pour saisir ces tags il faudra donc passer en mode d'édition HTML dans l'éditeur de Blogger
Le rendu n'est pas visible en mode édition, le mode "Aperçu" permet de voir ce que donnera l'affichage mais ne permet pas de tester les actions de la souris (sélection, copie, etc...)


5) Exemples

Exemple de code Java  ( brush:java )
public void foo() {
    int i = 0 ;
}

Exemple de code SQL  ( brush:sql )
select * from mytable
where code > 20 




mercredi 3 octobre 2012

JPA - Tracer les requêtes SQL avec Log4jdbc


L’utilisation de frameworks de persistance tels qu’ Hibernate, EclipseLink, TopLink ou OpenJPA permet de masquer toute la plomberie SQL et JDBC. Au point qu’on en oublierait presque qu’on travaille avec une base de données relationnelle.

Mais il y a toujours un moment où la réalité nous rattrape et où il devient indispensable de comprendre ce qui se passe de l’autre côté du décor. C'est à ce moment que le développeur s’interroge :  que fait concrètement notre framework de persistance ? Qu’est-ce qu’il nous cache ?

Bref, quelles sont les requêtes SQL envoyées à la base de données et à quel moment sont elles envoyées ?

Une première solution consiste à activer les traces du framework lui-même.

Par exemple avec JPA au niveau du fichier « persistence.xml » il suffit d’ajouter quelques propriétés de configuration.

Exemple pour  Hibernate :


Exemple pour EclipseLink :

Mais avec ce principe nous n’obtiendrons que ce que chaque framework veut bien nous donner. La configuration est propre à chaque environnement et le format des traces ne correspond pas forcément à ce que l’on souhaiterait.
Il s’agit donc d’une première réponse à la problématique des traces SQL, mais qui dans la plupart des cas se révélera insuffisante.

Ce serait tellement plus simple si on pouvait se situer entre le framework et la base de données pour voir passer les requêtes …  Et c’est là que les outils du type « proxy de driver JDBC » vont nous aider.

Avec un nom pareil on se doute bien du principe de fonctionnement …

Sans « proxy »


Avec « proxy »

Donc, on va « brancher » notre ORM sur un driver JDBC qui n’en est pas vraiment un. Cet usurpateur va être sollicité pour traiter les requêtes SQL qu’il va tracer, puis déléguer au « vrai » driver JDBC.

Il s’agit donc d’un « passe-plats » traceur.

Il existe différents outils de ce type, le plus connu étant certainement « P6Spy », célèbre espion au service de nos applications mais qui, contrairement à James Bond, a un peu vieilli (pas d’évolutions depuis plusieurs années).

Voici une liste (non exhaustive) de ce type d’outil :

Voyons maintenant comment utiliser Log4JDBC…

Pourquoi lui ? Parce qu’il est à jour (JDBC 4, JDK 1.6 et 1.7) et simple à installer (et pour P6Spy il y a déjà pas mal de doc en français sur la toile).

Architecture de Log4JDBC :






Log4JDBC permet d’utiliser différents types de loggers. Pour ce faire il s’appuie sur SLF4J : « Simple Logging Facade for Java » (http://www.slf4j.org/) une couche d’abstraction qui permet de s’isoler du logger concret qui sera utilisé (Log4J, java.util.logging, logback, etc… )
Dans le cas présent nous utiliserons Log4J (les classiques ça a du bon)

1) Récupérer les JAR nécessaires
  • SLF4J  ( 2 jars :  slf4j-api-x.x.x.jar  et  slf4j-log4j12-x.x.x.jar )
    http://www.slf4j.org/ :  Download  ( version 1.5 ou plus => prendre la dernière version )
On doit finalement avoir  4 JARs :




Il n’a plus qu’à ajouter ces JARs au projet, par exemple sous la forme d’une User Library sous Eclipse.

2) Insérer le « proxy » entre l’ORM et le « vrai driver JDBC »

2.1 ) Brancher Log4JDBC sur le « vrai driver JDBC »

Par défaut Log4JDBC cherche à utiliser les classes des drivers JDBC les plus courants

  • oracle.jdbc.OracleDriver ou oracle.jdbc.driver.OracleDriver pour Oracle
  • com.mysql.jdbc.Driver pour MySQL
  • org.postgresql.Driver pour PostgreSQL
  • etc…
Il connait une quinzaine de drivers classiques (voir la liste complète sur http://code.google.com/p/log4jdbc/ ). Pour ceux-là il n’y a donc aucune configuration à réaliser (il va trouver tout seul la classe du driver).

Si le driver JDBC n’est pas connu, il suffit de l’indiquer avec une « system property » :
     -Dlog4jdbc.drivers=<driverclass>[,<driverclass>...]

2.2 ) Brancher l’ORM sur le « faux driver » (Log4JDBC )

La classe qui simule de driver JDBC est « net.sf.log4jdbc.DriverSpy »
Il suffit donc de l’utiliser dans la configuration de l’ORM
Exemple dans « persistence.xml »



3) Configurer les loggers

Log4JDBC dispose de 5 loggers qui pourront être activés ou non en fonction des besoins :
  • jdbc.sqlonly    : trace uniquement le  SQL
  • jdbc.sqltiming  : trace le SQL et les statistiques de temps (durée d’exécution d’une requête SQL)
  • jdbc.audit      : trace tous les appels JDBC sauf pour les ResultSets
  • jdbc.resultset  : trace tous les appels aux objets ResultSet
  • jdbc.connection : trace les événements sur les connexions (open/close) et le nombre de connections ouvertes (utile pour identifier les « fuites » de connexions).
Il suffit de configurer au moins l’un de ces loggers dans le fichier « log4j.xml » pour voir les premières traces SQL.
Les loggers sont activés s’ils ont un des niveaux de trace  ERRORINFO  ou  DEBUG

Exemple de configuration Log4J :




4) Tester

Exemple de trace avec Hibernate :


Exemple de trace avec EclipseLink :


La configuration Log4J permet ensuite d’adapter le logger aux besoins (formatage des traces, nouveaux « appenders », etc… )


mardi 25 septembre 2012

Diagrammes en JavaScript

Quelques librairies JavaScript pour des diagrammes en tous genres


Diagrammes :

Dessin en 2D :


mardi 18 septembre 2012

Apache TomEE : Java EE 6 Web Profile.

Article de JavaWorld sur TomEE, l'implémentation Java EE 6 Web Profile d'Apache
http://www.javaworld.com/javaworld/jw-07-2012/120710-osjp-tomee.html

Issu du projet Open EJB, TomEE repose sur les grandes briques Java EE de la fondation Apache
( Tomcat, Open JPA, Open EJB, MyFaces, etc... )

Il se décline en 2 versions : TomEE et TomEE+

Détail de chaque distribution : http://tomee.apache.org/apache-tomee.html

Comparaison Tomcat / TomEE / TomEE+ / OpenEJB : http://tomee.apache.org/comparison.html

mardi 28 août 2012

Java - Optimisation et performance


Présentation de Charlie Hunt "Extreme Performance with Java" sur InfoQ  (mythes et réalités)
http://www.infoq.com/presentations/Extreme-Performance-Java


Série d'articles de Java World sur la JVM et ses performances

- Premier article d'une série consacrée aux performances Java
"JVM performance optimization, Part 1: A JVM technology primer"
Que fait réellement la JVM ? Comment se comporte le Garbage Collector ?  etc...
http://www.javaworld.com/javaworld/jw-08-2012/120821-jvm-performance-optimization-overview.html

- La suite : le compilateur (2eme partie )
"JVM performance optimization, Part 2: Compilers"
Compilation statique/dynamique, bytecode, inlined methods, ...
http://www.javaworld.com/javaworld/jw-09-2012/120905-jvm-performance-optimization-compilers.html

- 3ème partie : garbage collection
"JVM performance optimization, Part 3: Garbage collection"
http://www.javaworld.com/javaworld/jw-10-2012/121010-jvm-performance-optimization-garbage-collection.html

- 4ème partie : algorithme "C4" du GC
"JVM performance optimization, Part 4: C4 garbage collection for low-latency Java applications"
http://www.javaworld.com/javaworld/jw-11-2012/121107-jvm-performance-optimization-low-latency-garbage-collection.html

- 5ème partie : un peu de provocation dans le titre
"JVM performance optimization, Part 5: Is Java scalability an oxymoron?" 
http://www.javaworld.com/javaworld/jw-03-2013/130301-jvm-performance-optimization-java-scalability.html

Autres liens sur la JVM :




vendredi 20 juillet 2012

Modification dynamique du bytecode

Enfin un article qui explique comment travailler directement au niveau du bytecode (plutôt que par introspection) et qui démontre qu' ASM (http://asm.ow2.org/)  est la librairie la plus efficace en termes de performance.

http://www.ibm.com/developerworks/java/library/j-cwt05125/index.html


Et quelques rappels sur les fondamentaux du bytecode :
http://arhipov.blogspot.fr/2011/01/java-bytecode-fundamentals.html