<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="http://davidmasclet.gisgraphy.com/feed/rss2/xslt" ?><rss version="2.0"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:wfw="http://wellformedweb.org/CommentAPI/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <title>Blog de David MASCLET</title>
  <link>http://davidmasclet.gisgraphy.com/</link>
  <atom:link href="http://davidmasclet.gisgraphy.com:82/feed/rss2" rel="self" type="application/rss+xml"/>
  <description>Solutions aux problèmes fréquents de développeurs de projets open source (et autres)</description>
  <language>fr</language>
  <pubDate>Fri, 03 Feb 2012 03:20:37 +0100</pubDate>
  <copyright></copyright>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <generator>Dotclear</generator>
  
    
  <item>
    <title>Deviner la variable JAVA_HOME en bash</title>
    <link>http://davidmasclet.gisgraphy.com/post/2011/09/16/Deviner-la-variable-JAVA_HOME-en-bash</link>
    <guid isPermaLink="false">urn:md5:2ddc4e259cc5691aa65c63ed5a61979a</guid>
    <pubDate>Fri, 16 Sep 2011 16:41:00 +0200</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Linux</category>
            
    <description>    &lt;p&gt;Lors de l'écriture de l'un de mes scripts, j'ai du deviner la variable
JAVA_HOME. j'ai donc écrit une fonction en bash que je vous livre et qui pourra
sans doute vous aider&lt;/p&gt;
&lt;pre&gt;
#!/bin/bash
function guess_java_home(){
        for i in  `readlink -f \` which java\`` 
do 
        JAVA_HOME=${i/bin\/java/}
        echo &amp;quot;JAVA_HOME=${JAVA_HOME}&amp;quot;
done
}

&lt;/pre&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2011/09/16/Deviner-la-variable-JAVA_HOME-en-bash#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2011/09/16/Deviner-la-variable-JAVA_HOME-en-bash#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/637259</wfw:commentRss>
      </item>
    
  <item>
    <title>EasyMock en environnement multithread</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/11/28/EasyMock-en-environnement-multithread</link>
    <guid isPermaLink="false">urn:md5:ca681588338b5b88d73036fc6304734b</guid>
    <pubDate>Sun, 28 Nov 2010 13:39:00 +0100</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Tests / XUnit</category>
            
    <description>    &lt;p&gt;Lorsque vous voulez 'mocker' un objet et que ce dernier sera appelé par
plusieurs threads, vous aurez le message suivant &amp;quot;Un-thread-safe mock called
from multiple threads&amp;quot;.&lt;/p&gt;
&lt;p&gt;Par exemple :&lt;/p&gt;
&lt;pre&gt;
@test
public void MyTest(){
    List mockList = EasyMock.createMock(List.class);
    EasyMock.expect(mockList.add(EasyMock.anyObject())).times(NUMBER_OF_THREAD);
    EasyMock.replay(mockList);
                
    MyThread[] rateThread= new MyThread[NUMBER_OF_THREAD];
    for(int i=0;i&amp;lt;NUMBER_OF_THREAD;i++){
        rateThread[i]= new MyThread(){
           @Override     
               doit(){
                   mockList.add(&amp;quot;foo&amp;quot;);
               }
       };
     rateThread[i].start();
            
    }
}
&lt;/pre&gt;
&lt;p&gt;Il vous faut alors ajouter &lt;code&gt;EasyMock.makeThreadSafe(mockList,
true);&lt;/code&gt;. avant le &lt;code&gt;replay(mockList)&lt;/code&gt;&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/11/28/EasyMock-en-environnement-multithread#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/11/28/EasyMock-en-environnement-multithread#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/566047</wfw:commentRss>
      </item>
    
  <item>
    <title>Les génériques java et EasyMock</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/10/21/Les-g%C3%A9n%C3%A9riques-java-et-EasyMock</link>
    <guid isPermaLink="false">urn:md5:87e242d593bae135f1ef0863e2dd88c3</guid>
    <pubDate>Thu, 21 Oct 2010 21:42:00 +0200</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Java / J2EE</category>
            
    <description>    &lt;p&gt;Parfois nous devons exécuter un traitement et si le résultat est
&lt;code&gt;null&lt;/code&gt; nous voulons renvoyer un résultat par défaut. par exemple une
liste vide. cela permet d'éviter les &lt;code&gt;NullPointerException&lt;/code&gt;s si nous
parcourons la liste. Exemple :&lt;/p&gt;
&lt;pre&gt;
List&amp;lt;Contact&amp;gt; contacts = getContacts();
for (Contact contact : contacts){
      contact.setActive(true);
}
&lt;/pre&gt;
&lt;p&gt;Si &lt;code&gt;getContacts()&lt;/code&gt; renvoie &lt;code&gt;null&lt;/code&gt; le code renverra une
&lt;code&gt;NullPointerException&lt;/code&gt;. il est possible avec les
&lt;code&gt;génériques&lt;/code&gt; Java de le faire d'une manière élégante :&lt;/p&gt;
&lt;pre&gt;
 public static &amp;lt;T&amp;gt; T notNull(T test, T defaultvalue){
    return t == null ? test : defaultValue;
  }
&lt;/pre&gt;
&lt;p&gt;On peut alors écrire :&lt;/p&gt;
&lt;pre&gt;
List&amp;lt;Contact&amp;gt; contacts = notNull(getContacts(),new ArrayList&amp;lt;Contact&amp;gt;);
&lt;/pre&gt;
&lt;p&gt;Ce code n'est pas révolutionnaire mais il montre à quel point les génériques
de de Java peuvent être utiles. C'est d'ailleurs de cette manière que &lt;a href=&quot;http://easymock.org/&quot; hreflang=&quot;en&quot;&gt;EasyMock&lt;/a&gt; fonctionne. Lorsque vous
écrivez&lt;/p&gt;
&lt;pre&gt;
Myclass mock = EasyMock.createMock(MyClass.class);
EasyMock.expect(mock.function()).andReturn(value);
&lt;/pre&gt;
&lt;p&gt;Le type de &lt;code&gt;value&lt;/code&gt; est déterminé en générique Java par le retour
de &lt;code&gt;function()&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
 public &amp;lt;O&amp;gt; O expect(O t) {
        return t;
    }
&lt;/pre&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/10/21/Les-g%C3%A9n%C3%A9riques-java-et-EasyMock#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/10/21/Les-g%C3%A9n%C3%A9riques-java-et-EasyMock#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/556218</wfw:commentRss>
      </item>
    
  <item>
    <title>Hibernate : différence entre get() et load()</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/10/13/Hibernate-%3A-diff%C3%A9rence-entre-get%28%29-et-load%28%29</link>
    <guid isPermaLink="false">urn:md5:75f4a725ffefa15e536a4a90a1e694a0</guid>
    <pubDate>Wed, 13 Oct 2010 14:12:00 +0200</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Hibernate</category>
        <category>hibernate</category><category>Spring</category>    
    <description>&lt;p&gt;Si vous êtes un utilisateur d'Hibernate, que ce soit avec Spring ou pas,
vous êtes vous déjà posé la question de savoir quelles sont les différences
entre &lt;code&gt;session.load()&lt;/code&gt; et &lt;code&gt;session.get()&lt;/code&gt;. Comprendre les
différences permet souvent d'optimiser les accès à la base de données.&lt;/p&gt;    &lt;p&gt;En effet les signatures des deux méthodes sont assez proches et permettent
toutes les deux de récupérer une entité via sa clé. Voici donc les
différences :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get()&lt;/code&gt; renvoie &lt;code&gt;null&lt;/code&gt; si l'objet n'existe pas,
tandis que &lt;code&gt;load()&lt;/code&gt; lève une objectNotFoundException. Ce qui veux
dire que le fait que l'objet n'existe pas est considérer comme une erreur
applicative. Il faut donc utiliser &lt;code&gt;load()&lt;/code&gt; si tel est le cas. Par
contre la javadoc est claire : &lt;q&gt;You should not use this method to
determine if an instance exists (use get() instead)&lt;/q&gt;. en résumé n'en faites
pas une utilisation détournée ;)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;La deuxième différence est structurelle. Lorsque vous faites un
&lt;code&gt;get()&lt;/code&gt;, vous récupérez l'objet avec ses champs chargés (en fonction
des attributs &lt;code&gt;lazy&lt;/code&gt;, cela va sans dire). En revanche lorsque vous
faites un &lt;code&gt;load&lt;/code&gt;, Hibernate vous renvoie un proxy que sera
initialisé lors de l'appel à un champs ou a un getter. Si la session est fermé,
vous aurez alors une &lt;code&gt;LazyInitializationException&lt;/code&gt; :&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;
session.beginTransaction();

User user=(User) session.load(User.class, new Long(1));

session.getTransaction().commit();

user.getPassword();//=&amp;gt;LazyInitializationException

&lt;/pre&gt;
&lt;p&gt;Vous n'auriez pas eu cette exception si vous auriez utilisé
&lt;code&gt;get()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;La question qui vient alors à l'esprit est &amp;quot;si on ne doit pas utiliser
&lt;code&gt;load()&lt;/code&gt; pour tester l'existence d'un objet, et que les champs ne
sont pas initialisés, quand utilisez load()?&amp;quot;&lt;/p&gt;
&lt;p&gt;En fait, la réponse découle du modèle relationnel du SQL : lorsque vous
avez une association &lt;code&gt;OneToMany&lt;/code&gt; cela se traduit pas une relation de
clé primaire / étrangère. Chose qui n'existe pas dans le modèle Objet (d'où
l'intérêt d'Hibernate ;) ). pour associer un objet en SQL il suffit uniquement
de connaitre la clé primaire de l'objet associé. et c'est là qu'intervient
l'utilité de &lt;code&gt;load()&lt;/code&gt;. Nous n'avons besoin que de sa clé, pas des
champs. voici un exemple de code :&lt;/p&gt;
&lt;pre&gt;
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

User owner = session.get( User.class, 1 );//un appel
Car  car = session.get( Car.class, 2 );//deux appel
owner.setCar(car);//un save

tx.commit();
session.close();
&lt;/pre&gt;
&lt;p&gt;Cela fait deux appels à la database + un save (pas de cache dans notre
exemple). En revanche :&lt;/p&gt;
&lt;pre&gt;

Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();

User owner = session.load( User.class, 1 );
Car  car = session.get( Car.class, 2 );//un appel
owner.setCar(car);//un update

tx.commit();
session.close();
&lt;/pre&gt;
&lt;p&gt;Nous avons économisé un appel à la base.&lt;/p&gt;
&lt;p&gt;à vos refactoring :)&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/10/13/Hibernate-%3A-diff%C3%A9rence-entre-get%28%29-et-load%28%29#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/10/13/Hibernate-%3A-diff%C3%A9rence-entre-get%28%29-et-load%28%29#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/554230</wfw:commentRss>
      </item>
    
  <item>
    <title>Gérer les sessions Hibernate sans transaction</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/10/06/gerer-les-sessions-Hibernate-sans-transaction</link>
    <guid isPermaLink="false">urn:md5:fb126feaa508cb127fe7042e7d08b511</guid>
    <pubDate>Wed, 06 Oct 2010 22:45:00 +0200</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Hibernate</category>
        <category>hibernate</category><category>spring</category>    
    <description>&lt;p&gt;Comme vous le savez déjà peut être, les sessions Hibernate sont très
fortement couplées aux transactions : Hibernate ouvre et ferme les
sessions au début et à la fin d'une transaction. Lors du développement d'une
librairie (DAO), Je me suis posé la question &amp;quot;est il possible de ne pas
utiliser un contexte transactionnel pour gérer les sessions ?&amp;quot;. En effet lors
de mes tests qui sont transactionnels, tout se passait bien mais lorsque
j'intégrais mon code dans un contexte non transactionnel et que je tentais de
récupérer des associations liées à une entité, j'avais des
&lt;code&gt;lazyInitializationException&lt;/code&gt; car les sessions était fermées.
j'avais alors plusieurs solutions :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Utiliser le filtre Spring &lt;code&gt;Opensessioninviewfilter&lt;/code&gt;, mais cela
rend ma librairie non portable car cela ne fonctionnera que dans un contexte
web&lt;/li&gt;
&lt;li&gt;Faire des méthodes ad'hoc pour récupérer l'entité ou l'entité avec ses
associations chargées (eager), mais au détriment d'un code moins lisible et où
il est facile de ne pas utiliser la bonne méthode&lt;/li&gt;
&lt;li&gt;Charger les associations directement (par configuration) avec
FetchType=Eager. pas assez performant !&lt;/li&gt;
&lt;li&gt;Utiliser les &lt;a href=&quot;http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e3524&quot; hreflang=&quot;en&quot;&gt;profiles de fectching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Faire une gestion des session par thread.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Je vous propose de voir comment j'ai implémenté la dernière solution&lt;/p&gt;    &lt;p&gt;Pour ne pas avoir à gérer mes sessions / transactions à la main, j'utilise
Spring, c'est donc à ce dernier que revient la tâche de les ouvrir et de les
fermer. Spring fournit plusieurs &amp;quot;facilities&amp;quot; pour gérer les DAOs, dont celui
d'Hibernate : &lt;code&gt;HibernateDaoSupport&lt;/code&gt;. Cette classe permet de
&amp;quot;wrapper&amp;quot; les méthodes d'Hibernate pouvant faire du CRUD et de s'affranchir de
la gestion des sessions. elle permet également de réalisé un traitement
(&lt;code&gt;callback&lt;/code&gt;) au sein d'une session via une template hibernate
(&lt;code&gt;hibernatTemplate&lt;/code&gt;). Spring ouvre alors une session, exécute le
callback, puis il se chargera de fermé la session :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Soit à la fin de la transaction&lt;/li&gt;
&lt;li&gt;Soit à la fin de la requête HTTP dans le cas de l'utilisation de
&lt;code&gt;Opensessioninviewfilter&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le code d'un callback ressemble alors à cela :&lt;/p&gt;
&lt;pre&gt;
public monDao extends HibernateDaoSupport

 public Collection loadProductsByCategory(String category) throws DataAccessException {
        return this.getHibernateTemplate().find(
            &amp;quot;from test.Product product where product.category=?&amp;quot;, category);
    }
&lt;/pre&gt;
&lt;p&gt;Le déroulement est donc le suivant :
HibernateDaoSupport-&amp;gt;getHibernatTemplate()-&amp;gt;getSession()-&amp;gt;Création /
réutilisation d'une session selon paramétrage-&amp;gt;exécution du callback-&amp;gt;
fermeture de la session&lt;/p&gt;
&lt;p&gt;il me suffit donc de redéfinir la méthode &lt;code&gt;getsession()&lt;/code&gt; de
&lt;code&gt;HibernateCallback&lt;/code&gt;. Pour cela, il faut que je change l'appel à
&lt;code&gt;getHibernateTemplate()&lt;/code&gt;. Pas de chance! cette méthode est
&lt;code&gt;final&lt;/code&gt; (sick !). je vais devoir rusé. je vais donc remonter
jusqu'au HibernateDaoSupport, et créé le mien :
&lt;code&gt;NotTransationnalHibernateDaoSupport&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Je reprends donc le code, puis redéfinis la méthode
&lt;code&gt;getHibernateTemplate()&lt;/code&gt;, qui me renverra non plus une
&lt;code&gt;HibernateTemplate&lt;/code&gt; mais une
&lt;code&gt;NonTransactionnalHibernateTemplate&lt;/code&gt;, qui elle même redéfinira
&lt;code&gt;getSession()&lt;/code&gt;, qui elle même s'appuiera sur une politique de
gestion des sessions par Thread.&lt;/p&gt;
&lt;p&gt;Pour la gestion par thread je me dis que partir du code de
&lt;code&gt;Opensessioninviewfilter&lt;/code&gt; est un bon départ, car elle permet déjà de
faire une gestion des sessions particulière : il me faut ouvrir une
session, l'affecter dans un &lt;code&gt;ThreadLocal&lt;/code&gt;, et la fermer lorsque le
&lt;code&gt;Thread&lt;/code&gt; disparait&lt;/p&gt;
&lt;pre&gt;
package org.springframework.orm.hibernate3.support;

import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.orm.hibernate3.SessionFactoryUtils;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

public class OpenSessionInThread extends Thread {

    public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = &amp;quot;sessionFactory&amp;quot;;

    private FlushMode flushMode = FlushMode.MANUAL;

    private SessionFactory sessionFactory;

    public OpenSessionInThread(SessionFactory sessionFactory) {
        super();
        this.sessionFactory = sessionFactory;
        Runtime.getRuntime().addShutdownHook(this);
    }

    public Session getSession() {
        Session session = null;
        if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
            session = ((SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory)).getValidatedSession();
        } else {
            session = getSession(sessionFactory);
            TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
        }

        return session;
    }

    protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
        Session session = SessionFactoryUtils.getSession(sessionFactory, true);
        FlushMode flushMode = this.flushMode;
        if (flushMode != null) {
            session.setFlushMode(flushMode);
        }
        return session;
    }

    protected void closeSession() {
        Session session;
        if (this.sessionFactory != null) {
            if (TransactionSynchronizationManager.hasResource(this.sessionFactory)) {
                session = ((SessionHolder) TransactionSynchronizationManager.getResource(this.sessionFactory)).getValidatedSession();
                SessionFactoryUtils.closeSession(session);
            } else {
                System.err.println(&amp;quot;can not close session, session is not in thread&amp;quot;);
            }
        } else {
            System.err.println(&amp;quot;can not close the session because session factory is null&amp;quot;);
        }

    }

    @Override
    public void run() {
        closeSession();

    }
}

&lt;/pre&gt;
&lt;p&gt;Il faut maintenant que j'intègre cela dans la méthode
&lt;code&gt;getSession()&lt;/code&gt; de ma classe
&lt;code&gt;NotTransactionnalHibernateTemplate&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
package org.springframework.orm.hibernate3;

import java.sql.SQLException;

import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.support.OpenSessionInThread;
import org.springframework.util.Assert;

public class NotTransactionalHibernateTemplate extends HibernateTemplate {

    private OpenSessionInThread openSessionInThread;

    public NotTransactionalHibernateTemplate(SessionFactory sessionFactory, boolean allowCreate) {
        super(sessionFactory, allowCreate);
    }

    @Override
    public boolean isCheckWriteOperations() {
        return false;
    }

    /**
     * @param sessionFactory
     */
    public NotTransactionalHibernateTemplate(SessionFactory sessionFactory) {
        super(sessionFactory);
        openSessionInThread = new OpenSessionInThread(sessionFactory);
    }

    @Override
    public boolean isAllowCreate() {
        return false;
    }

    @Override
    public boolean isAlwaysUseNewSession() {
        return false;
    }

    @Override
    protected Session getSession() {
        Session session = openSessionInThread.getSession();
        session.setFlushMode(FlushMode.AUTO);
        return session;

    }

    @Override
    protected &amp;lt;T&amp;gt; T doExecute(HibernateCallback&amp;lt;T&amp;gt; action, boolean enforceNewSession, boolean enforceNativeSession) throws DataAccessException {

        Assert.notNull(action, &amp;quot;Callback object must not be null&amp;quot;);
        Session session = (enforceNewSession ? SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
        boolean existingTransaction = (!enforceNewSession &amp;amp;&amp;amp; (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
        if (existingTransaction) {
            logger.debug(&amp;quot;Found thread-bound Session for HibernateTemplate&amp;quot;);
        }

        try {
            Session sessionToExpose = (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
            T result = action.doInHibernate(sessionToExpose);
            session.flush();
            return result;
        } catch (HibernateException ex) {
            session.clear();
            throw convertHibernateAccessException(ex);
        } catch (SQLException ex) {
            session.clear();
            throw convertJdbcAccessException(ex);
        } catch (RuntimeException ex) {
            session.clear();
            throw ex;
        }
    }

}

&lt;/pre&gt;
&lt;p&gt;Ca y est ! maintenant ma gestion des sessions est liée au cycle de vie
du &lt;code&gt;Thread&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Je redéfinis ensuite la méthode &lt;code&gt;getHibernateTemplate()&lt;/code&gt; de ma
classe &lt;code&gt;NonTransationnalHibernateDaoSupport&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
                return new NotTransactionalHibernateTemplate(sessionFactory);
        }
&lt;/pre&gt;
&lt;p&gt;maintenant je change l'héritage dans mes DAOs pour qu'il étendent
NonTransationnalHibernateDaoSupport.&lt;/p&gt;
&lt;p&gt;Il me reste cependant un dernier détail a gérer : il ne faut pas que la
session soit fermée ailleur que dans ma classe de gestion de sessions, or en
regardant où est utilisée &lt;code&gt;getSession()&lt;/code&gt;, je me rend compte que dans
la méthode &lt;code&gt;doExecute()&lt;/code&gt;, la session peut être fermée dans certain
cas. Je modifie donc le code. vous remarquerez que je fais un clear de la
session si une exception est levée afin de ne pas exécuter d'autre
traitement :&lt;/p&gt;
&lt;pre&gt;
 @Override
    protected &amp;lt;T&amp;gt; T doExecute(HibernateCallback&amp;lt;T&amp;gt; action, boolean enforceNewSession, boolean enforceNativeSession) throws DataAccessException {

        Assert.notNull(action, &amp;quot;Callback object must not be null&amp;quot;);
        Session session = (enforceNewSession ? SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor()) : getSession());
        boolean existingTransaction = (!enforceNewSession &amp;amp;&amp;amp; (!isAllowCreate() || SessionFactoryUtils.isSessionTransactional(session, getSessionFactory())));
        if (existingTransaction) {
            logger.debug(&amp;quot;Found thread-bound Session for HibernateTemplate&amp;quot;);
        }

        try {
            Session sessionToExpose = (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session));
            T result = action.doInHibernate(sessionToExpose);
            session.flush();
            return result;
        } catch (HibernateException ex) {
            session.clear();
            throw convertHibernateAccessException(ex);
        } catch (SQLException ex) {
            session.clear();
            throw convertJdbcAccessException(ex);
        } catch (RuntimeException ex) {
            session.clear();
            throw ex;
        }
    }
&lt;/pre&gt;
&lt;p&gt;Afin de testé si cela fonctionne, je désactive les transactions dans mes
tests, et étend&lt;code&gt;AbstractJUnit4SpringContextTests&lt;/code&gt; au lieu de
&lt;code&gt;AbstractTransactionalJUnit4SpringContextTests&lt;/code&gt;, je rajoute
également une méthode pour effacer les enregistrements dans mes tables à la fin
de chaque test :&lt;/p&gt;
&lt;pre&gt;
// public abstract class AbstractDatabaseTestCase extends AbstractTransactionalJUnit4SpringContextTests{
public abstract class AbstractDatabaseTestCase extends AbstractJUnit4SpringContextTests{

@After
    public void cleanAll() {
        dao1.flushAndClear(); 
        dao1.deleteAll(dao1.getAll());
        
        dao2.flushAndClear(); 
        dao2.deleteAll(dao2.getAll());
....

    }


&lt;/pre&gt;
&lt;p&gt;Reste à vérifier si cela fonctionne !&lt;/p&gt;
&lt;p&gt;En l'absence de transaction, si mes DAO étendent
&lt;code&gt;NonTransationnalHibernateDaoSupport&lt;/code&gt;, les associations chargées en
lazy ne font plus de &lt;code&gt;lazyInitializationException&lt;/code&gt; alors que c'est
le cas si mes DAOs étendent &lt;code&gt;HibernateDaoSupport&lt;/code&gt; CQFD !&lt;/p&gt;
&lt;p&gt;pour ceux qui sont intéressé, j'ai joint les sources à ce billet.&lt;/p&gt;</description>
    
          <enclosure url="http://davidmasclet.gisgraphy.com/public/hibernatewotransaction.zip"
      length="6033" type="application/zip" />
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/10/06/gerer-les-sessions-Hibernate-sans-transaction#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/10/06/gerer-les-sessions-Hibernate-sans-transaction#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/552635</wfw:commentRss>
      </item>
    
  <item>
    <title>Autocomplétion dans l'interpréteur interactif Python</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/08/12/Autocompletion-dans-l-interpreteur-interactif-Python2</link>
    <guid isPermaLink="false">urn:md5:e709705bf8823522505eeb4cec1b9df7</guid>
    <pubDate>Thu, 12 Aug 2010 09:47:00 +0200</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>python</category>
            
    <description>    &lt;p&gt;Je vous propose une petite astuce pour activer l'autocomplétion ainsi qu'un
historique des commandes tapées dans l'interpréteur Python. Python 2.0 minimum
est requis&lt;/p&gt;
&lt;pre&gt;
#!/usr/bin/env python
# Add auto-completion and a stored history file of commands to your Python
# interactive interpreter. Requires Python 2.0+, readline. Autocomplete is
# bound to the Esc key by default (you can change it - see readline docs).
#
# Store the file in ~/.pystartup, and set an environment variable to point
# to it, e.g. &amp;quot;export PYTHONSTARTUP=/max/home/itamar/.pystartup&amp;quot; in bash.
#
# Note that PYTHONSTARTUP does *not* expand &amp;quot;~&amp;quot;, so you have to put in the
# full path to your home directory.

import rlcompleter
import readline
readline.parse_and_bind(&amp;quot;tab: complete&amp;quot;)
import os
histfile = os.path.join(os.environ[&amp;quot;HOME&amp;quot;], &amp;quot;.pyhist&amp;quot;)
try:
    readline.read_history_file(histfile)
except IOError:
    pass
import atexit
atexit.register(readline.write_history_file, histfile)
del histfile, readline, rlcompleter
&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;Sauvegarder le code ci dessus dans un fichier : ~/.pystartup&lt;/li&gt;
&lt;li&gt;Définissez une variable d'environnement pointant vers ce fichier dans le
fichier bashrc : (~/.bashrc) :&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;
export PYTHONSTARTUP=/home/user/.pystartup  
&lt;/pre&gt;
&lt;p&gt;David&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/08/12/Autocompletion-dans-l-interpreteur-interactif-Python2#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/08/12/Autocompletion-dans-l-interpreteur-interactif-Python2#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/539160</wfw:commentRss>
      </item>
    
  <item>
    <title>Le cloud computing</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/06/01/Le-cloud-computing</link>
    <guid isPermaLink="false">urn:md5:362ac48f54205f9d3387a656f848159b</guid>
    <pubDate>Thu, 10 Jun 2010 15:43:00 +0200</pubDate>
    <dc:creator>Masclet</dc:creator>
            
    <description>&lt;p&gt;Le cloud computing est un concept ou les applications sont exécutées par une
puissance de calcul dont on ne gère plus l'infrastructure sous-jacente, on
parle alors de puissance de calcul ou de stockage à la demande. Par analogie on
peut comparer le cloud computing à la consommation électrique : on fait
varier la production en fonction de la demande.&lt;/p&gt;    &lt;h3&gt;Pourquoi&lt;/h3&gt;
&lt;p&gt;Tout d'abord pour permettre une sécurité de fonctionnement accrue, une
scalabilité plus facile, une maitrise (un besoin ponctuel) et une diminution
des couts (moins de main d 'oeuvre), une professionnalisation (moins de savoir
faire nécessaire)&lt;/p&gt;
&lt;h3&gt;Pour quelles applications ?&lt;/h3&gt;
&lt;p&gt;Le cloud computing est très adapté pour les applications de services dites
SaaS (Software as a service), car l'utilisation de ces services peuvent varier
en charge dans le temps.&lt;/p&gt;
&lt;h3&gt;Exemples d'API&lt;/h3&gt;
&lt;p&gt;L'api la plus connue est sans doute l'api d'Amazon. Amazon qui au départ
n'était qu'un site internet à fort trafic, a su mettre à profit leur expertise
dans la scalabilité, et fournissent désormais des services de cloud computing.
Amazon Elastic Compute Cloud plus connus sous le nom de EC2 génère plus de
trafic que le site d'Amazon lui même et fait partit des nombreux service
commercialisés sous le nom d'Amazon Web Services ou &lt;a href=&quot;http://fr.wikipedia.org/wiki/Amazon_Web_Services&quot; hreflang=&quot;fr&quot;&gt;AWS&lt;/a&gt;. AWS
propose entre autre un services de stockage à la demande appelé S3, de base de
données (SimpleDB) ainsi que des services de micro paiement (FPS),
d'authentification (Amazon AWS Authentication) et des services métiers sur la
librairie en ligne d'Amazon. EC2 permet via une interface web de pouvoir créer,
supprimer, démarrer et arrêter des serveurs dont la facturation se fait au
temps d'utilisation. Bien qu'on ne gère pas les serveurs et l'aspect technique
il est tout de même possible de créer des serveurs virtuels sur des instances
de serveurs physiques différentes afin de permettre la tolérance aux pannes.
Ceci évite les coupures de services si l'un des serveur physique tombe et que
tous les serveurs virtuels étaient installés dessus.&lt;/p&gt;
&lt;p&gt;Eucalyptus (Elastic Utility Computing Architecture for Linking Your Programs
To Useful Systems) est une solution open source disponible en standard sur les
versions d'Ubuntu supérieure a 9.04. Eucalyptus est compatible avec Amazon Web
Services. il s'installe aussi sur d'autre plateformes comme CentOS ou
Debian.&lt;/p&gt;
&lt;p&gt;Tout les 'grands' s'y sont mis :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Windows Azure et Azure Services pour Microsoft&lt;/li&gt;
&lt;li&gt;Blue Cloud d'IBM&lt;/li&gt;
&lt;li&gt;HP dispose une son offre New Generation Data Center (NGDC) pour virtualiser
des machine HP-UX&lt;/li&gt;
&lt;li&gt;projet Hydrazine de Sun&lt;/li&gt;
&lt;li&gt;Google App Engine pour Google qui lui se base plus sur des API spécifiques
en Java ou python plutôt que sur de la virtualisation pure.&lt;/li&gt;
&lt;li&gt;Salesforce, lui, fournit des logiciels de gestion de relation client.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On assiste aussi à des rapprochement : IBM et Google ont signé un
accord visant à mettre en commun leurs ressources de cloud computing. et Google
vise à connecter ses applications bureautiques de Google aux environnements de
Salesforce.&lt;/p&gt;
&lt;p&gt;Pour ceux que ça intéresse, je vous conseille la lecture de cet article qui
explique comment Ebay conçoit ses architectures pour permettre le passage à
l'échelle : &lt;a href=&quot;http://www.infoq.com/articles/ebay-scalability-best-practices&quot; hreflang=&quot;en&quot;&gt;http://www.infoq.com/articles/ebay-scalability-best-practices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Autres liens :&lt;br /&gt;
&lt;a href=&quot;http://blog.octo.com/comment-segment-l-offre-de-cloud-computing/&quot; hreflang=&quot;fr&quot;&gt;http://blog.octo.com/deploiement-dune-application-sur-linfrastructure-amazon-13/&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://blog.octo.com/comment-segment-l-offre-de-cloud-computing/&quot; hreflang=&quot;fr&quot;&gt;http://blog.octo.com/comment-segment-l-offre-de-cloud-computing/&lt;/a&gt;&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/06/01/Le-cloud-computing#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/06/01/Le-cloud-computing#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/523595</wfw:commentRss>
      </item>
    
  <item>
    <title>10 minutes pour comprendre...NoSQL</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/06/09/10-minutes-pour-comprendre...NoSQL</link>
    <guid isPermaLink="false">urn:md5:dc1c642daf2fee547b1c73b98af8d84c</guid>
    <pubDate>Wed, 09 Jun 2010 14:31:00 +0200</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>10 minutes pour...</category>
            
    <description>&lt;p&gt;Lorsque l'on parle de sites à fort trafic et de bases de données, on
n'entend rarement parler de bases de données relationnelles. En effet, garantir
la consistance des données coute chère en temps et est souvent incompatible
avec les performances.&lt;/p&gt;
&lt;p&gt;Puisque le modèle relationnel ne semble pas adapté dans des environnement
nécessitant de grosses architectures et que les propriétés &lt;a href=&quot;http://fr.wikipedia.org/wiki/Transaction_informatique#Les_caract.C3.A9ristiques_ACID&quot; hreflang=&quot;fr&quot;&gt;ACID&lt;/a&gt; des bases ne permettent généralement pas de passer à
l'échelle, un nouveau mouvement (encore un ;)) est née de l'initiative des
architectes de &lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/06/01/Le-cloud-computing&quot;&gt;cloud
computing&lt;/a&gt; et des sites communautaire comme Facebook, Amazon et
Linkin : le NoSQL, (aka : &lt;em&gt;Not Only SQL&lt;/em&gt;). Ce billet tente de
faire le tour d'horizon des différents types de bases &lt;code&gt;NoSQL&lt;/code&gt;, les
différentes solutions disponibles sur le marché et dans quels cas les
utiliser.&lt;/p&gt;    &lt;h5&gt;Le partitionnement&lt;/h5&gt;
&lt;p&gt;Le point de contention des applications est bien souvent la base de données
qui lorsqu'elles sont transactionnelles, distribuées, ne permettent pas
facilement le passage à l'échelle. Que l'on fasse du lock optimiste, pessimiste
ou transaction à deux phases, on couple toujours les données entre elles, ce
qui empêche la sérialisation. En plus, pour la sécurité de fonctionnement, il
faut que les données soient répliquées, se qui complique encore un peu plus les
choses. Dans les architectures modernes, la validation du modèle se fait
désormais dans les objets, au niveau de l'applicatif. Cela permet de soulager
la base et de ne se concentrer que sur les requêtes. des mouvements comme le
DDD ont remis au gout du jour les objets avec du code métier plutôt que des
POJOs.&lt;/p&gt;
&lt;p&gt;Lorsque l'on veux scaler une base de données,une première solution peut être
le partitionnement :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vertical : une base pour les livres, une base pour les CDs, etc&lt;/li&gt;
&lt;li&gt;Horizontal : une base pour les livre de A-M et une pour les livres de
N-Z, ...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C'est donc une segmentation intelligente qui permet une montée en charge.
mais cette architecture montre tout de même des limites, c'est là que le NoSQL
entre en jeu&lt;/p&gt;
&lt;h5&gt;Le théorème de CAP&lt;/h5&gt;
&lt;p&gt;La quasi totalité des sites à fort trafic n'utilisent pas de base de données
relationnelles avec des propriétés &lt;a href=&quot;http://fr.wikipedia.org/wiki/Transaction_informatique#Les_caract.C3.A9ristiques_ACID&quot; hreflang=&quot;fr&quot;&gt;ACID&lt;/a&gt; mais plutôt des bases de données dites
&lt;code&gt;NoSQL&lt;/code&gt; basées sur le théorème de CAP d’Eric Brewer, qui est plus
adaptés aux données massivement partagés.&lt;/p&gt;
&lt;p&gt;En voici les 3 principes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consistance (consistency /C) : Tous les clients voient la même vue
même lorsqu’il y a des mises-à-jour, en fait il s'agit du 'Atomic' des
propriétés ACID.&lt;/li&gt;
&lt;li&gt;Haute disponibilité (availability /A) : L’ensemble des clients peuvent
trouver des données répliquées, même lorsqu’une avarie survient&lt;/li&gt;
&lt;li&gt;Tolérant à la partition (partition-tolerance /P) : Le système est
tolérant au partitionnement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En revanche, seul deux des trois principes peuvent être respectés en même
temps, souvent ce sont les deux derniers principes qui sont choisis (c'est le
cas d 'Amazon par exemple) car le besoin en disponibilité et en partitionnement
est souvent plus important que la consistance.&lt;/p&gt;
&lt;p&gt;Les utilisateurs n'ont pas forcément tous la même vue à un moment donné,
mais est-ce vraiment une nécessité ? Dans certains cas oui mais souvent
non. Si vous faites une recherche sur Google et que vous n'avez pas exactement
la même réponse qu'un autre utilisateur cela parait moins important que de ne
pas avoir de résultats de recherche du tout (pas de haute
disponibilité) !&lt;/p&gt;
&lt;p&gt;Souvent, si la consistance est importante pour certaines données, il est
d'usage de les isoler dans des bases relationnelles et de placer les autres
données dans des bases dite &lt;code&gt;NoSQL&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Certaines données nous paraissent logiques d'être consistantes mais cela est
souvent du à notre inertie d'esprit. Prenons le cas d'une valeur indiquant le
stock d'un article. Si deux serveurs ont des valeurs non consistantes, il peut
arriver qu'un serveur considère qu'il en reste un alors qu'un autre qui a était
mis à jour, sait qu'il n'en reste plus. Lorsque vous faites un achat et si par
malchance vous acheter un livre qui n'est plus en stock, le site marchand à
deux possibilités : vous rembourser ou réapprovisionner le stock (je ne
sais pas vous, mais cela m'est déjà arrivé de recevoir un mail en disant que le
produit était épuisé,après l'avoir commandé)&lt;/p&gt;
&lt;p&gt;Dans cet exemple, vous pouvez avoir des désagrément mais je pense
qu'entre&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;acheter sur un site très lent (disons quelques dizaine de secondes de
latence par page) mais où le stock est en tant réel entre les milliers de
serveurs pour tous les produits du site&lt;/li&gt;
&lt;li&gt;une éventualité de stock non cohérente mais une haute disponibilité,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;les sites ont fait leur choix ! Amazon a d'ailleurs constaté qu'un
dixième de seconde de latence leur fait diminuer les ventes de 1%, et Google a
remarqué qu'une demi seconde de latence fait chuter le trafic d'un
cinquième.&lt;/p&gt;
&lt;p&gt;Le fait d'accepter des données inconsistantes est connu sous le nom de BASE
(Basically Available, Soft-state, Eventually consistent) qui est en fait,
l'opposé des propriétés ACID. Le fait d'accepter que deux des trois principes
du théorème de CAP peuvent être satisfait en même temps a fait le succès des
&lt;a href=&quot;http://www.google.com/adplanner/static/top1000/&quot; hreflang=&quot;en&quot;&gt;plus
gros sites de la planète&lt;/a&gt;, alors si cela a marché pour eux, je ne vois pas
pourquoi cela ne marcherai pas pour d'autres.&lt;/p&gt;
&lt;h5&gt;Les 4 types de bases NoSQL&lt;/h5&gt;
&lt;p&gt;il existe 4 catégories de base NoSQL.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Orientées colonnes, comme HBase, Hypertable ou Cassandra, elles sont basées
sur le concept de BigTable de Google&lt;/li&gt;
&lt;li&gt;Basées sur la théorie des graphes (Euler) implémenter par Neo4J.&lt;/li&gt;
&lt;li&gt;Orientées clé-valeur (Voldemort, Dynomite, Riak).&lt;/li&gt;
&lt;li&gt;Orientées document, comme CouchDB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voyons maintenant leurs spécificités plus en détail :&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;Bases de données orientés colonnes :&lt;/h4&gt;
&lt;p&gt;Alors que les colonnes sont statiques pour une base relationnelle, elles
sont dynamiques pour une base de données orientée colonnes, il est alors
possible d'ajouter des colonnes dynamiquement et il n'y a pas de coût de
stockage pour les valeurs &lt;code&gt;Null&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Pour des raisons de performances les colonnes sont triées sur le disques,
minimisant les accès aléatoires. De plus pour Cassandra, les écritures sont
séquentielles pour éviter les latences de disques durs, les données sont tout
d'abord écrites en mémoire, puis, persistées sur le disque lors d'un
&lt;code&gt;commitlog&lt;/code&gt; ou lorsque la mémoire est pleine.&lt;/p&gt;
&lt;p&gt;Les BDD orientées colonnes sont prévues pour stocker des millions de
colonnes, ce qui en fait des bases adaptées au stockage
&lt;code&gt;one-to-many&lt;/code&gt;. L'inconvénient est bien sur la mise à jour. Alors que
pour une base de donnée relationnelle, une mise à jour du tuples disposant
d'une clé étrangère peux suffire, une BDD orientée colonnes peut nécessiter une
mise à jour de toutes les valeurs d'une colonne pour tous les
enregistrements.&lt;/p&gt;
&lt;p&gt;Il existe également des &lt;code&gt;super colonnes&lt;/code&gt; qui sont des conteneurs
de colonnes.&lt;/p&gt;
&lt;p&gt;Les requête sont assez minimalistes, par exemple :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Toutes les colonnes ayant comme clé 256&lt;/li&gt;
&lt;li&gt;Les colonnes dont le nom est compris entre 'bbb' et 'bbc' et dont la clé
est 8652&lt;/li&gt;
&lt;li&gt;La colonne 'abc' pour les lignes allant de 500 à 1000.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cassandra (initialement utilisé par Facebook pour les messages non
instantanés) et HBase sont des solutions de BDD orientées colonnes. Cassandra
permettait à Facebook d'accéder aux messages échangés entre utilisateurs et aux
messages comportant certains mots.&lt;/p&gt;
&lt;p&gt;Ces bases sont destinées à des usages où l'on doit stocker des données par
utilisateur et des données uniques. Ne chercher pas à faire du relationnel avec
cette base, la mailing liste est pleine de ce genre de questions mais ce n'est
tout simplement pas fait pour !&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;Bases de données orientées graphes.&lt;/h4&gt;
&lt;p&gt;Les bases de données orientés graphes n'ont pas pour but premier de résoudre
des problèmes de performances mais plutôt de palier à des problèmes impossibles
à résoudre avec des BDD relationnelles.&lt;/p&gt;
&lt;p&gt;Le cas d'utilisation typique est bien sur les réseaux sociaux où l'aspect
graphe prend tout son sens, mais aussi où des relations complexes entre les
acteurs ont besoin d'être décrits (pièces d'une machine, arbre généalogique).
Les bases de données orientés graphes ne représenteront probablement pas la
majeure partie des BDD NoSQL.&lt;/p&gt;
&lt;p&gt;Neo4J semble être actuellement la solution la plus mature.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;Base de données clé-valeur&lt;/h4&gt;
&lt;p&gt;Dynamo, développé par Amazon, semble la plus connue des BDD clé-valeur. En
simplifiant à l'extrême, les bases de données clé-valeur sont de grosses tables
de hashage, leur légitimité se trouve dans le fait que les entités sont, dans
une grande partie des cas, rapatriées à partir d'un identifiant. Toutefois le
fonctionnement de ces bases est loin d'être aussi simple : les tables sont
partitionnées. La partition est choisie en fonction d'un hash de la clé, qui
donnera l'instance qui se chargera du stockage. Tout réside donc dans
l'algorithme de la fonction de hashage qui doit garantir une répartition la
plus égale possible entre les partitions.&lt;/p&gt;
&lt;p&gt;Les données, à la différence d'une table de hashage, sont redondées. Afin de
ne pas être sur un modèle 1 partition = 1 partition répliquée = 1 machine,
chaque machines se voit attribuer une ou plusieurs partitions offrant ainsi de
meilleurs performances et une tolérance aux pannes accrue.&lt;/p&gt;
&lt;p&gt;Une des particularité de ces bases est que l'on peux choisir le niveau de
consistance. ce niveau est défini par un &lt;code&gt;quorum&lt;/code&gt; correspondant aux
nombres de réponses de la part des partitions pour lequel on considère les
données consistante. Si l'on veux que les données soit 100 % consistantes
(toutes lectures sur n'importe quelles partitions donneront le même résultat),
on définit alors le &lt;code&gt;quorum&lt;/code&gt; au maximum. Le quorum peux être
différent en lecture et en écriture, par contre des conflits de versions
peuvent apparaitre, c'est alors à l'application cliente de résoudre les
conflits (quelle version garder? un peu comme quand vous résolvez les conflits
avec SVN).&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;Bases de données orientées documents&lt;/h4&gt;
&lt;p&gt;Elles sont une évolution des bases de données clé-valeur, où à une clé, est
associé un document dont la structure est libre. il faut cependant que la base
soit consciente de ce qu'elle stocke afin de permettre des fonctionnalités sur
les documents. Je trouve que ces bases ressemblent beaucoup, au niveau
stockage, à des utilisations comme SOLR / Lucene, ou a &lt;a href=&quot;http://www.inria.fr/rocquencourt/partenariats/relations-industrielles/creation-d-entreprises-et-espace-tranfert/xyleme&quot; hreflang=&quot;fr&quot;&gt;Xylème&lt;/a&gt; de l'INRIA (j'ai fais mon mémoire d'ingénieur sur ce
projet).&lt;/p&gt;
&lt;p&gt;De part son modèle, ces BDD se pré destine au stockage d'informations
&lt;code&gt;one-to-one&lt;/code&gt; et &lt;code&gt;one-to-many&lt;/code&gt; et au stockage
d'informations de session, de données de fichiers, pages web, etc&lt;/p&gt;
&lt;h5&gt;Un mot sur la sérialisation des données&lt;/h5&gt;
&lt;p&gt;Lorsque les données sont dispersées, et que l'on doit faire des traitement
dessus, il faux souvent les véhiculer. Les grands comptes optent souvent pour
des solutions évitant les sérialisation à outrance, les données ne sont pas
véhiculées sur le réseau, seul l'endroit où elle se trouvent l'est. La donnée
doit être accédée le plus tardivement possible ce qui permet d'économiser du
réseaux, de la mémoire et du CPU. De plus les traitements doivent être
insensibles à l'ordre d'arrivée des messages : la synchronisation tue les
systèmes distribués !&lt;/p&gt;
&lt;h4&gt;conclusion&lt;/h4&gt;
&lt;p&gt;Pour le moment, le NoSQL est un mouvement grandissant, bien qu'il soit
utilisé par les grand comptes qui sont à l'origine du mouvement. il n'y a pas
de solutions qui se démarque vraiment du lot, il n'y a que des solutions
adaptés aux besoins. On remarquera aussi qu'il manque vraiment des standards,
comme JDBC et SQL le sont pour les SGBDR, mais cela s'explique sans doute par
la jeunesse du mouvement et l'hétérogénéité des type de bases.&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/06/09/10-minutes-pour-comprendre...NoSQL#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/06/09/10-minutes-pour-comprendre...NoSQL#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/525674</wfw:commentRss>
      </item>
    
  <item>
    <title>Les différents modèles économiques de l'open source</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/04/09/Diff%C3%A9rents-mod%C3%A8les-%C3%A9conomique-de-l-open-source</link>
    <guid isPermaLink="false">urn:md5:36d0f335ca1b9bb8ff33f11cb204ab8e</guid>
    <pubDate>Wed, 19 May 2010 10:05:00 +0200</pubDate>
    <dc:creator>Masclet</dc:creator>
            
    <description>&lt;p&gt;Souvent lorsque je parle de &lt;a href=&quot;http://www.gisgraphy.com/&quot; hreflang=&quot;en&quot;&gt;Gisgraphy&lt;/a&gt;, la question qui m'est posée est &amp;quot;quelles sont tes
motivations&amp;quot; et &amp;quot;est-ce que tu gagnes de l'argent avec ce projet&amp;quot;. Après leur
avoir expliquer que le projet est open source et libre. La réaction est quasi
toujours la même : &amp;quot;tu n'a pas peur que quelqu'un te pique le
projet ? et comment peut on gagner de l'argent alors que tout est gratuit
?&amp;quot;. J'ai donc décidé de faire ce billet pour expliquer mes motivations ainsi
que les différentes façons de gagner de l'argent avec des projets open source
et libres. autant vous le dire tout de suite : je perds de l'argent avec
Gisgraphy, mais mon but n'est pas forcément d'en gagner (même si j'aimerais ne
pas être de ma poche ;) )&lt;/p&gt;    &lt;h4&gt;Un peu de vocabulaire&lt;/h4&gt;
&lt;p&gt;J'avoue que dans ce billet je mélange un peu les termes : Open source,
gratuit, libre. bien que différents, je vais parler d'une façon générale des
différents moyens de gagner de l'argent quand on fait un logiciel libre et / ou
open source.&lt;/p&gt;
&lt;h4&gt;Gagner de l'argent avec de l'open source&lt;/h4&gt;
&lt;p&gt;Le modèle de licence des logiciels propriétaires est appelé &lt;em&gt;EULA&lt;/em&gt;
(End User License Agreement) en anglais et traduit par CLUF (Contrat de Licence
Utilisateur Final) en français. Le principe est très simple : Donne moi de
l'argent en échange de mon logiciel. et maintenant débrouille toi avec ce que
je t'ai vendu ! Microsoft, comme comme beaucoup d'éditeurs de logiciels
propriétaires fonctionne de cette façon. Le principe est simple et le modèle
économique évident : l'achat !&lt;/p&gt;
&lt;p&gt;Lorsqu'on développe un logiciel open source, il faut se creuser un peu plus
les méninges. Comment un logiciel gratuit et dont le code est disponible peut
rapporter de l'argent ? pourtant ce modèle est déjà rependu dans notre
quotidien, mais peut être ne vous en rendez vous plus compte :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les journaux quotidiens gratuits (20 minutes, Direct soir, métro)&lt;/li&gt;
&lt;li&gt;Google Maps&lt;/li&gt;
&lt;li&gt;Firefox et Thunderbirds&lt;/li&gt;
&lt;li&gt;Wikipédia&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Les différents modèles&lt;/h4&gt;
&lt;p&gt;Voici quelques modèles utilisés pour gagner de l'argent avec de l'open
source / libre :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support Ware : Donnez nous de l'argent et nous répondrons à vos
questions (au moins nous ferons de notre mieux). mail, téléphone, forums, peu
importe. &lt;a href=&quot;http://www.redhat.com/&quot; hreflang=&quot;en&quot;&gt;Red hat&lt;/a&gt; fonctionne
sur ce principe.&lt;/li&gt;
&lt;li&gt;Product Ware : Le logiciel est gratuit, vous achetez juste 'le
matériel' dans lequel il tourne . &lt;a href=&quot;http://www.android.com/&quot; hreflang=&quot;en&quot;&gt;Android&lt;/a&gt;, &lt;a href=&quot;http://www.google.com/enterprise/&quot; hreflang=&quot;en&quot;&gt;Google Apps &amp;amp; Search Appliance&lt;/a&gt; utilise ce principe (Google ne
fournit pas l'hébergement)&lt;/li&gt;
&lt;li&gt;Cloud Ware : Donne de l'argent pour ce que le logiciel. L'argent ira
je ne sais où (dans les nuages ;) ), mais tu auras le bénéfice des retombées.
&lt;a href=&quot;http://www.sugarcrm.com/crm/&quot; hreflang=&quot;en&quot;&gt;SugarCRM&lt;/a&gt; est basé sur
ce modèle.&lt;/li&gt;
&lt;li&gt;Project Ware : Besoin de réaliser un projet ? nous pouvons le
faire pour vous en open source ! Payez nous pour notre travail et pour le
projet. &lt;a href=&quot;http://www.ibm.com/fr/fr/&quot; hreflang=&quot;en&quot;&gt;IBM&lt;/a&gt; réalise des
tonnes de projets sur ce modèle&lt;/li&gt;
&lt;li&gt;SaaS Ware : Notre logiciel est un logiciel de service (SaaS :
Software as a Service), vous pouvez le louer à l'heure, à la semaine, au
mois,....Ce modèle est très populaire. &lt;a href=&quot;http://www.zoho.com/&quot; hreflang=&quot;en&quot;&gt;Zoho&lt;/a&gt; comme beaucoup d'autre fonctionne sur ce modèle. Geonames, lui
mise sur des données édités par tous et fournit des services gratuits et payant
par dessus.&lt;/li&gt;
&lt;li&gt;Ad Ware : Vous ne payez rien, les agences publicitaires le feront pour
vous. c'est le modèle principale de Google (bien que pas open source ;) ).&lt;/li&gt;
&lt;li&gt;Sugar Daddy Ware : Le logiciel a un papa bien veillant. Eclipse est
développé par IBM. Open Office par Sun / Oracle. Ne vous souciez de rien, papa
est là, il assure l'évolution du logiciel.&lt;/li&gt;
&lt;li&gt;Foundation Ware : Le logiciel est supporté par une fondation. Il a
beaucoup de contributeurs et de donateurs. Apache, Mozilla, Wikipedia sont
parmi les plus connues.&lt;/li&gt;
&lt;li&gt;Beg Ware : Donner nous de l'argent, aucune raison invoquées, juste
donnez nous de l'argent. c'est le modèle le plus répandu pour les projets de
petites tailles.&lt;/li&gt;
&lt;li&gt;Tchotchke Ware : Le logiciel est payé par l'achat de goodies (Tshirt,
stylo, mug, ...), Allez visiter &lt;a href=&quot;http://www.google-store.com/&quot; hreflang=&quot;en&quot;&gt;le magasin en ligne de google&lt;/a&gt; ou &lt;a href=&quot;http://shop.ubuntu.com/&quot; hreflang=&quot;en&quot;&gt;d'ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Let’s Make a Deal Ware : Les développeurs supportent le coût de
développement jusqu'à ce que d'autres le fasse, Wordpress, Drupal ont commencés
comme cela. Sourceforge héberge des tas de projet basés sur ce modèle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cette liste n'est pas exhaustive. et certains logiciels / distributeurs
cumulent les modèles pour maximiser les revenus. Il est cependant à noter que
ces modèles sont relativement fragiles et les revenus non maitrisés. Les dons
sont assez sporadiques, et le site de wikipédia nous incite souvent à faire des
dons en mettant en avant combien &amp;quot;il manque dans la caisse&amp;quot; :&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/.wikipedia-banner_s.jpg&quot; alt=&quot;wikipedia banner&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;wikipedia banner, mai 2010&quot; /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;Le monde du libre et du gratuit me parait vraiment être une bonne
chose : Lorsque l'on voit encarta qui a fermé son site à cause de
Wikipedia, je me dis que la force du libre est la sensation que le travail
qu'on fournit va servir à tout le monde. Les gens sont prêts à s'investir si
des sociétés ne s'engraissent pas sur leurs dos. Mettre un logiciel en open
source apporte son lot d'avantages : on décuple le nombre de personnes, de
contributions, d'idées, la réactivité dans la résolution de bugs, et on diminue
aussi le nombre de développeurs à payer...&lt;/p&gt;
&lt;p&gt;Des problème peuvent également apparaitre. Dans un système décentralisé,
lorsque les personnes responsables du projet prennent des chemins différents,
comme ce fut le cas de &lt;a href=&quot;http://www.mamboserver.com/&quot; hreflang=&quot;en&quot;&gt;Mambo&lt;/a&gt; et &lt;a href=&quot;http://www.joomla.fr/&quot; hreflang=&quot;fr&quot;&gt;Joomla&lt;/a&gt;.
Dans ce cas une guerre s'ouvre et les utilisateurs subissent les dommages
collatéraux : Lequel choisir, le projet est il viable, ne va-t-il pas
s'arrêter, quel est le meilleur ? Les problèmes peuvent aussi apparaitre
pour les prises de décisions : Quand tout le monde décide, plus rien
n'avance si les gens n'arrivent pas à se mettre d'accord.&lt;/p&gt;
&lt;p&gt;Je me pose également une question : &amp;quot;En ce qui concerne les données
gratuites, à qui appartiennent les données et qui en a la
responsabilité&amp;quot; ? une réponse idyllique serait &amp;quot;à tout le monde&amp;quot;, sauf que
ces données sont bien stockées quelque part, et si ces hébergeurs / fondations
venaient à cesser d'héberger ces données, il y aurait toujours les backups,
mais qui supporterait le coût de l'hébergement, qui reprendrait ces
données ? (une société, une fondation existante ou nouvelle, une personne
dont les motivations sont autres?) Les données de Openstreetmap et Geonames,
par exemple, me semble quand même bien centralisées (plus que Wikipedia). Si
ces sites venaient à fermer il n'y aurait que leurs licences pour les protéger.
une protection suffisante ?&lt;br /&gt;&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/04/09/Diff%C3%A9rents-mod%C3%A8les-%C3%A9conomique-de-l-open-source#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/04/09/Diff%C3%A9rents-mod%C3%A8les-%C3%A9conomique-de-l-open-source#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/507358</wfw:commentRss>
      </item>
    
  <item>
    <title>Automatiser les interactions avec des scripts shell ou bash</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/03/25/Automatiser-les-interactions-avec-des-scripts-bashs</link>
    <guid isPermaLink="false">urn:md5:b1832561e45e29604deff4baf9d0f67b</guid>
    <pubDate>Thu, 25 Mar 2010 13:37:00 +0100</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Linux</category>
        <category>bash</category><category>linux</category><category>test</category>    
    <description>&lt;p&gt;Peut être avez vous déjà eu besoin de simuler des réponses à des scripts
shell. Par exemple lorsque vous avez un script qui demande une confirmation, un
mot de passe ou tout autre intervention humaine, et que vous désirez tester le
comportement du script. il existe un outil assez pratique pour le faire qui se
nomme &lt;a href=&quot;http://expect.sf.net/&quot; hreflang=&quot;en&quot;&gt;expect&lt;/a&gt;. Il permet
d'automatiser les interactions avec des applications non-GUI (aka :
graphiques). plusieurs versions sont disponibles expect-tcl8.3 ou expectk.&lt;/p&gt;    &lt;p&gt;Expect est un langage de script pour s'interfacer avec des programmes comme
FTP, Telnet, fsck, ssh et d'autres qui ne peuvent normalement pas être
automatisée à partir d'un script shell. Il est donc également bon pour
automatiser l'exécution de programmes sur des systèmes distants. Il s'installe
par apt (debian / Ubuntu) ou yum&lt;/p&gt;
&lt;pre&gt;
apt-get install expectk
&lt;/pre&gt;
&lt;p&gt;Vous devez pour cela lister les questions et explicitement en donner les
réponses. les wildcards sont permis afin d'être plus souple sur les
questions&lt;/p&gt;
&lt;p&gt;Voici un exemple qui répond automatiquement à un script se connectant en SSH
(bouh pas bien ! :) )&lt;/p&gt;
&lt;pre&gt;
expect - &amp;lt;&amp;lt;ENDSCRIPT
  spawn ssh $_user@$_server '$_command'
  match_max 100000

  expect {
       &amp;quot;Are you sure you want to continue connecting (yes/no)&amp;quot;
       {
          sleep 1
          send &amp;quot;yes\r&amp;quot;
          exp_continue
       }
       &amp;quot;*password:*&amp;quot;
       {
          sleep 1
          send &amp;quot;PASSWORD\r&amp;quot;
          exp_continue
      }
  }
ENDSCRIPT 
&lt;/pre&gt;
&lt;p&gt;En voici un autre pour un SCP :&lt;/p&gt;
&lt;pre&gt;
#!/usr/bin/expect  --
 set timeout 30
 spawn scp user@ip:~/myfile  .
 expect {
                      &amp;quot;password:&amp;quot; {
                                send &amp;quot;password\r&amp;quot;
                    } &amp;quot;yes/no)?&amp;quot; {
                                send &amp;quot;yes\r&amp;quot;
                                set timeout -1
                    } timeout {
                                exit
                    } eof {
                                exit
                    }
 }
&lt;/pre&gt;
&lt;p&gt;Combiné avec &lt;a href=&quot;http://shunit.sourceforge.net/&quot; hreflang=&quot;en&quot;&gt;ShUnit&lt;/a&gt;, il permet d'automatiser les tests facilement.&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/03/25/Automatiser-les-interactions-avec-des-scripts-bashs#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/03/25/Automatiser-les-interactions-avec-des-scripts-bashs#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/502465</wfw:commentRss>
      </item>
    
  <item>
    <title>Détecter et corriger les fuites mémoire java</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/02/05/D%C3%A9tecter-et-corriger-les-fuites-m%C3%A9moire-java</link>
    <guid isPermaLink="false">urn:md5:65a9815b7b4f6e02789a20fd82c50d9b</guid>
    <pubDate>Mon, 01 Mar 2010 09:16:00 +0100</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Java / J2EE</category>
        <category>Fuites mémoire</category><category>java</category>    
    <description>&lt;p&gt;Ceux qui ont déjà développé en C, puis en Java auront probablement apprécié
la gestion de la mémoire par la JVM. En effet, Java masque la complexité de la
gestion de la mémoire aux développeurs. Cette tache est déléguée au
&lt;code&gt;garbage Collector&lt;/code&gt;. Cependant même si cette gestion est dite
'automatique', cela ne permet pas de faire n'importe quoi. Que ce soit en C,
Java, ou un autre langage, la mémoire est une ressource limitée ! En java
lorsque la JVM n'a plus assez de mémoire pour s'exécuter, elle génère une
Erreur &lt;code&gt;java.lang.OutOfMemoryError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Plusieurs cas sont alors possible :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Soit vous n'avez pas alloué assez de mémoire à la JVM&lt;/li&gt;
&lt;li&gt;Soit votre code a ce qu'on appelle un fuite mémoire&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si vous êtes dans le premier cas, les choses se résolvent assez
facilement : il vous suffit d'allouer plus de mémoire grâce aux paramètres
&lt;code&gt;-Xmx&lt;/code&gt;, &lt;code&gt;-Xms&lt;/code&gt; et &lt;code&gt;-XX:PermSize&lt;/code&gt; (ou de
modifier le code pour qu'il gaspille moins de mémoire). Dans le deuxième cas
vous allez devoir trouver où se situe la fuite mémoire. Si vous avez utilisé
des logiciels pour vous y aider, vous avez peut être été perdu par toutes les
possibilités qu'ils offrent et par la profusion d'informations qu'il
fournissent.&lt;/p&gt;
&lt;p&gt;Le but de ce billet est d'expliquer comment détecter et corriger les fuites
mémoires avec Eclipse Memory Analyser Tool un outil gratuit et très utile qui
aide vraiment à trouver les fuites mémoires. Nous allons voir comment extraire
les informations pertinentes, les comprendre, et trouver les responsables des
fuites mémoire en ayant une approche pragmatique. Je vous propose de nous
appuyer sur du code simple (disponible en fichier attaché à ce billet) générant
une fuite mémoire.&lt;/p&gt;    &lt;h3&gt;La gestion de la mémoire en Java&lt;/h3&gt;
&lt;p&gt;La JVM dispose de plusieurs zones mémoire distinctes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La pile (ou heap), est l'espace mémoire où tous les objets et tableaux sont
stockés. Lorsque la JVM démarre, la pile est initialisée à la valeur spécifiée
par &lt;code&gt;-Xms&lt;/code&gt; et elle grandira dynamiquement quand les objets seront
crées, jusqu'à ce qu'elle atteigne sa taille maximale spécifiée par le
paramètre &lt;code&gt;-Xmx&lt;/code&gt;. Si la taille maximale est atteinte, et que plus de
mémoire est nécessaire, la JVM générera une &lt;code&gt;java.lang.OutOfMemoryError:
Java heap space&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Permgen space : il s'agit de l'espace mémoire qui est alloué pour le
chargement des classes (pas les objets). A la différence de la pile, la taille
de cette région est fixe et ne varie plus après le démarrage de la JVM. Pour la
JVM de Sun, la taille par défaut du permGen space est de 64M. Vous pouvez
changer cette valeur grâce au paramètre &lt;code&gt;-XX:PermSize&lt;/code&gt;. Rappelons
tout de même que les options commençant par &lt;code&gt;XX&lt;/code&gt; ne sont pas des
paramètres HotSpot stables et que leurs compatibilités dépendent du vendeur et
de la version de la JVM. Si la mémoire du permgen est insuffisante une
&lt;code&gt;java.lang.OutOfMemoryError: PermGen space&lt;/code&gt; sera renvoyée&lt;/li&gt;
&lt;li&gt;il existe un troisième type d'erreurs : les erreurs natives. Elles
apparaissent lorsque le système hôte ne peut plus fournir de mémoire (plus
assez de place en mémoire vive, ou plus assez de swap). Dans ce cas la JVM
génère une Erreur &lt;code&gt;java.lang.OutOfMemoryError: request &amp;lt;size&amp;gt; bytes
for &amp;lt;reason&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cas des champs statiques : Les champs statiques ne peuvent être garbage
collectés tant que la classe qui les référence est chargée. il ne peuvent être
garbage collectés que lorsque le class loader qui est responsable du chargement
de la classe est lui même garbage collecté.&lt;/p&gt;
&lt;p&gt;Chaque instance de classe a une taille en mémoire, cette taille appelée
&amp;quot;Shallow Heap&amp;quot; est constituée de types primitifs (int, char, ...). Une instance
peut avoir également des références sur d'autres objets qui ont eux même une
taille. Les objets ainsi liés entre eux constituent un graphe.&lt;/p&gt;
&lt;p&gt;Tous les graphes disposent d'une racine d'attache, ces racines peuvent être,
par exemple, des threads ou des class loaders qui tiennent des références sur
les attributs statiques. Ces racines se nomment en anglais des &amp;quot;GC root&amp;quot;.
Toutes les instances en mémoire finissent par être attachées à une racine, si
ce n'est pas le cas, le Garbage Collector peut supprimer ces instances du
graphe, et libérer de la mémoire.&lt;/p&gt;
&lt;p&gt;Les références peuvent être de plusieurs types. Il y avait les références
fortes &amp;quot;StrongReference&amp;quot; et depuis java 5 il existe des références dites douces
&amp;quot;SoftReference&amp;quot; : L'objet est référencé, mais si la JVM a besoin de
mémoire, elle peut libérer cet objet. On trouve également les références
légères &amp;quot;WeakReference&amp;quot;: L'objet restera en mémoire, tant qu'il existe une
référence forte ou douce sur lui. enfin il existe des
&lt;code&gt;PhantomReference&lt;/code&gt; : les objets peuvent être supprimés de la
mémoire si aucune référence forte, douce, ou légère existe sur cette objet.&lt;/p&gt;
&lt;h3&gt;Empreinte de la mémoire (Heap dump)&lt;/h3&gt;
&lt;p&gt;Afin de permettre des diagnostiques et de voir ce que contient la mémoire de
la JVM, il est possible de générer une &amp;quot;empreinte de la mémoire&amp;quot; qui correspond
à tous les objets chargés à un instant précis. Ces empreintes sont plus connus
sous le nom de &amp;quot;Heap dump&amp;quot;.&lt;/p&gt;
&lt;p&gt;Ces dumps contiennent :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tous les objets : champs, références, et objet primitifs.&lt;/li&gt;
&lt;li&gt;Toutes les classes : Class loader, super Class, champs statiques&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;En revanche il ne contient pas les informations sur qui et où sont crées les
objets, ni quels sont les objets qui ont déjà été garbage collectés.&lt;/p&gt;
&lt;p&gt;Il existe différentes méthodes pour générer ces dumps. Soit en spécifiant
les options &lt;code&gt;-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/dump.hprof&lt;/code&gt; au lancement de la JVM afin qu'un dump
soit généré lorsqu'une &lt;code&gt;java.lang.OutOfMemoryError&lt;/code&gt; survient. Notez
toutefois que comme toutes les options commençant par &lt;code&gt;XX&lt;/code&gt;, elles
sont dépendantes du vendeur de JVM. La deuxième solution est de faire un dump à
la demande, à l'aide du &lt;code&gt;JDK 6&lt;/code&gt; et de &lt;code&gt;JConsole&lt;/code&gt;. les
dumps à la demande sont utiles, par exemples, après des benchs.&lt;/p&gt;
&lt;p&gt;Voici la procédure :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lancez &lt;code&gt;JConsole&lt;/code&gt; situé dans le répertoire &amp;quot;bin&amp;quot; de la JVM&lt;/li&gt;
&lt;li&gt;Sélectionnez le processus Java pour lequel vous voulez faire le dump.
Vérifiez sur l'onglet &amp;quot;VM summary&amp;quot; que c'est bien le bon processus.&lt;/li&gt;
&lt;li&gt;Rendez vous sur l'onglet Mbeans&lt;/li&gt;
&lt;li&gt;Sélectionnez l'item com.sun.management / hotspot diagnostic / operation /
dumpheap&lt;/li&gt;
&lt;li&gt;Spécifiez le chemin complet du fichier où vous voulez stocker le dump dans
le premier champs de saisie (laissez le deuxième champs à true). Les dumps ont
souvent l'extension hprof, et MAT ne verra pas le fichier s'il n'a pas la bonne
extension.&lt;/li&gt;
&lt;li&gt;Validez en cliquant sur le bouton &amp;quot;dumpHeap&amp;quot;. Cela figera l'exécution de la
JVM (donc à éviter en production), exécutera un garbage collector, et générera
un fichier binaire avec le contenu de la mémoire.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.jconsole_m.jpg&quot; alt=&quot;jconsole&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;jconsole, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Si vous ne possedez pas JDK 6.0, il est possible d'utiliser &lt;a href=&quot;http://java.sun.com/javase/6/docs/technotes/tools/share/jmap.html&quot; hreflang=&quot;en&quot;&gt;jmap&lt;/a&gt; :&lt;/p&gt;
&lt;pre&gt;
jmap -heap:format=b &amp;lt;PID_DU_PROCESS_JAVA&amp;gt;
&lt;/pre&gt;
&lt;h3&gt;Qu'est ce qu'une fuite mémoire&lt;/h3&gt;
&lt;p&gt;Une fuite mémoire est une dérive non contrôlée de l'utilisation de la
mémoire. elle est souvent due à un objet qui garde des références à une
multitude d'autres, ce qui empêche le garbage collector de les enlever de la
mémoire. Cette dernière grandit alors de plus en plus et finit par saturer.&lt;/p&gt;
&lt;p&gt;Pour comprendre une fuite mémoire il faut connaitre quelques termes (en
anglais):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dominator tree : Liste des plus gros objets et de qui les
référencent.&lt;/li&gt;
&lt;li&gt;Leak suspect : Objet ayant une grosse taille dans le dominator
tree.&lt;/li&gt;
&lt;li&gt;Accumulation point : Gros objet référençant beaucoup d'autres petits
objets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voici un représentation graphique des termes évoqués ci dessus :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.dominator_tree_m.jpg&quot; alt=&quot;IMAGE&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;dominator tree, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Shallow Heap et retained Heap : il s'agit de la taille que prend un
objet sur la pile. &amp;quot;shallow heap&amp;quot; représente la taille des éléments de l'objet
sans inclure les objets qu'il référence, tandis que &amp;quot;retained Heap&amp;quot; les prend
en compte : elle représente la taille qui sera libéré si cet objet est
garbage collecté. Voici un exemple pour mieux comprendre :&lt;/p&gt;
&lt;p&gt;Ci dessous ce trouve la représentation interne d'une string que j'ai pu
obtenir avec le mode debug d'Eclipse :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/retained_size.jpg&quot; alt=&quot;retained size&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;retained size, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;On voit qu'une string est représentée par trois entiers : count, hash,
et offset, qui représente la shallow heap, ainsi qu'une référence &amp;quot;value&amp;quot; à un
tableau de char&lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/02/05/&quot;&gt;&lt;/a&gt; . count, hash, offset et value représente la
retained heap car le char&lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/02/05/&quot;&gt;&lt;/a&gt; sera également garbage collecté si la
string l'est aussi.&lt;/p&gt;
&lt;h3&gt;Eclipse Memory Analyser Tool&lt;/h3&gt;
&lt;p&gt;Il existe déjà des outils permettant d'analyser les dumps, mais ils sont
soit difficiles d'approche comme &lt;a href=&quot;http://java.sun.com/javase/6/docs/technotes/tools/share/jhat.html&quot; hreflang=&quot;en&quot;&gt;jhat&lt;/a&gt; (Java Heap Analysis Tool) et jmap soit ils sont payants comme
Jprofiler.&lt;/p&gt;
&lt;p&gt;Eclipse a développé un outil permettant d'analyser les heap dumps. Cela
permet d'aider à trouver où se situent les fuites mémoires et de détecter les
gaspillages et améliorations possibles de l'utilisation de la mémoire. L'outil
ne se contente pas de vous analyser la mémoire, il cherche également où peuvent
se situer les fuites ainsi que les optimisations. c'est là le point fort de cet
outil.&lt;/p&gt;
&lt;p&gt;MAT peut être installé en tant que plugin dans Eclipse, ce qui a l'avantage
de pouvoir regarder le code en même temps que de regarder le dump, ou en tant
que client lourd (RCP) à part entière, des scripts sont alors disponibles en
plus du plugins. Peu importe votre choix, vous pouvez vous rendre sur &lt;a href=&quot;http://www.eclipse.org/mat/downloads.php&quot; hreflang=&quot;en&quot;&gt;cette page&lt;/a&gt; pour le
télécharger.&lt;/p&gt;
&lt;h3&gt;Utilisation de MAT avec un code d'exemple&lt;/h3&gt;
&lt;p&gt;Je vous propose de tester MAT avec du code simple (disponible en fichier
attaché à ce billet) générant une fuite mémoire. Le code représentera plusieurs
objets métiers : une entreprise, des salariés, et des adresses, ainsi
qu'une classe permettant de générer quelques instances de ces objets et une
&lt;code&gt;HashMap&lt;/code&gt; statique servant de cache pour les objets
&lt;code&gt;Entreprise&lt;/code&gt;. Enfin une fois tous ces objets chargés, je provoquerai
une fuite mémoire en remplissant un tableau avec des &lt;code&gt;Double&lt;/code&gt;. Je
dis bien &amp;quot;provoquerai&amp;quot;, car à la différence des Exceptions, les Errors sont
générées par la JVM et non par le code : si je fais&lt;/p&gt;
&lt;pre&gt;
throw new OutOfMemoryError();
&lt;/pre&gt;
&lt;p&gt;et que je spécifie les options &lt;code&gt;HeapDumpOnOutOfMemoryError&lt;/code&gt; le
dump ne sera pas généré.&lt;/p&gt;
&lt;p&gt;je lance donc la classe Application avec les options
&lt;code&gt;-XX:+HeapDumpOnOutOfMemoryError -Xms5m -Xmx10m
-XX:MaxPermSize=256m&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;En l'absence de &lt;code&gt;HeapDumpPath&lt;/code&gt;, c'est un fichier avec le PID qui
sera généré, l'avantage étant qu'un nouveau fichier de dump sera généré à
chaque &lt;code&gt;java.lang.OutOfMemoryError&lt;/code&gt; (il ne sera pas écrasé puisque
le nom sera différent à chaque fois)&lt;/p&gt;
&lt;p&gt;Le lancement du programme me donne la sortie suivante :&lt;/p&gt;
&lt;pre&gt;
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid2331.hprof ...
Heap dump file created [13486084 bytes in 0.401 secs]
Exception in thread &amp;quot;main&amp;quot; java.lang.OutOfMemoryError: Java heap space
        at java.util.ArrayList.ensureCapacity(ArrayList.java:169)
        at java.util.ArrayList.add(ArrayList.java:351)
        at com.demo.mat.OutOfMemoryHelper.addDouble(OutOfMemoryHelper.java:18)
        at com.demo.mat.OutOfMemoryHelper.throwOutOfMemoryError(OutOfMemoryHelper.java:13)
        at com.demo.mat.Application.main(Application.java:74)

&lt;/pre&gt;
&lt;p&gt;Il ne reste plus qu'a analyser le dump. vous pouvez l'ouvrir directement en
lançant MAT, puis en allant dans &lt;code&gt;File-&amp;gt;Open Heap Dump&lt;/code&gt; et en
sélectionnant le fichier java_pid2331.hprof. (seuls les fichiers .hprof
apparaitrons). MAT générera alors plusieurs indexes et un rapport HTML. Les
indexes permettent de naviguer plus rapidement car le format hprof n'est pas
très exploitable en l'état. Cette génération n'aura lieu qu'une seul fois et
lorsque vous rouvrirez ce dump, Mat utilisera les fichier déjà générés.&lt;/p&gt;
&lt;p&gt;Dans notre cas le fichier sera de 10 méga octets (environ taille du Xmx),
mais si vous voulez analyser de gros fichiers je vous conseille d'utiliser la
ligne de commande:&lt;/p&gt;
&lt;pre&gt;
./MemoryAnalyzer -consolelog -application org.eclipse.mat.api.parse java_pid2331.hprof
&lt;/pre&gt;
&lt;p&gt;car MAT a des fois du mal à les digérer. L'ouverture par MAT sera alors plus
rapide et facile.&lt;/p&gt;
&lt;p&gt;vous pouvez aussi utiliser le scipt ParseHeapDump.sh, il vous faudra par
contre remplacer les ^M, pour cela ouvrez le fichier en mod binaire avec
VIM :&lt;/p&gt;
&lt;pre&gt;
vim - b ParseHeapDump.sh
puis :%s/&amp;lt;CTRL+V&amp;gt;&amp;lt;CTRL+M&amp;gt;//g pour remplacer le ^M par chaine vide
&lt;/pre&gt;
&lt;h3&gt;Prise en main de l'outil&lt;/h3&gt;
&lt;p&gt;Le rapport donne une première vue avec&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;les informations sur la taille du dump (8.7M) et le nombre de classe
chargées (360)&lt;/li&gt;
&lt;li&gt;un camembert représentant les plus gros objets en mémoire. En passant votre
souris sur chaque partie du camembert, vous pouvez avoir des informations sur
les attributs (références et champs natifs) de l'objet dans la colonne de
gauche 'attributes'&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.mat_report_m.jpg&quot; alt=&quot;mat report&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;mat report, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Différentes actions menant vers différentes vues du dump :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Un histogramme : qui affiche une représentation de l'utilisation
mémoire par classes (nombre d'objets instanciés par classe, ainsi que leurs
tailles 'shallow' et 'retained'). Vous pouvez d'ailleurs voir que le nombre de
&lt;code&gt;char&lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/02/05/&quot;&gt;&lt;/a&gt;&lt;/code&gt; est sensiblement le même que le nombre de
&lt;code&gt;String&lt;/code&gt; ;)&lt;/li&gt;
&lt;li&gt;Un dominator tree (voir définition ci dessus) : présente non plus une
vue par classes mais par objets&lt;/li&gt;
&lt;li&gt;Une vue graphique des objets du dominator tree groupés selon différents
critères : class loaders, packages, classes. Le dominator tree travaille,
si on ne spécifie pas de groupage, au niveau objet&lt;/li&gt;
&lt;li&gt;Une liste des classes chargées plusieurs fois par différents class
loader.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les parties les plus intéressantes du rapport et les plus exploitables
directement sont sans aucun doute les deux rapports suivants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Liste des 'leak suspects', c'est à dire que l'outil vous suggère où peuvent
se situer les responsables de fuites mémoires.&lt;/li&gt;
&lt;li&gt;Une liste des objets gaspillant la mémoire (e.g : ArrayList
surdimensionnées ayant beaucoup d'éléments vides) avec des suggestions
d'optimisations de l'utilisation mémoire (à ne pas confondre avec le rapports
des fuites mémoires.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voyons vue par vue, les choses que nous pouvons faire : Dans toutes les
vues vous avez la possibilité de voir ce que contient l'objet sélectionné dans
l'onglet &amp;quot;attributes&amp;quot;.&lt;/p&gt;
&lt;p&gt;Il est possible de calculer la taille de la 'retained heap' via l'icône
représentant un calculatrice.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.calculate_retained_heap_size_m.jpg&quot; alt=&quot;calculate retained size&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;calculate retained size, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Vous pouvez ainsi trier les objets par 'retained heap' pour identifier les
'leak supect'. Vous pouvez aussi les filtrés en rentrant des expressions
régulières juste en dessous des libellés de colonnes (e.g : &amp;quot;regex&amp;quot; en
dessous de 'Class Name'). Attention pour les regexp, elles sont sensibles à la
casse.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.histograme_filtres_m.jpg&quot; alt=&quot;histograme filtres&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;histograme filtres, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Une action qui révèle souvent des informations intéressantes, consiste à
grouper les objets. Si vous les groupez par classe, vous pouvez par exemple
obtenir le nombre d'objets et le pourcentage de la mémoire totale qu'occupe les
objets de cette classe. Cela permet d'identifier les points d'accumulation plus
facilement lorsque la fuite mémoire ne concerne pas un seul gros objet (ce qui
n'est pas notre cas) mais une multitude d'objets de la même classe. Par défaut,
la distribution de l'occupation de la mémoire ce fait par objet, en les
groupant, les shallow / retained heap sont alors additionnés, laissant souvent
voir une répartition inégale de l'utilisation de la mémoire selon les classes
(&lt;a href=&quot;http://dev.eclipse.org/blogs/memoryanalyzer/2008/05/08/the-power-of-aggregation-making-sense-of-the-objects-in-a-heap-dump/&quot; hreflang=&quot;en&quot;&gt;en savoir plus&lt;/a&gt;). Vous pouvez aussi les grouper par class
loader, ce qui peut se révéler intéressant pour des webapps, Tomcat, par
exemple, utilise des class loader differents : webappClassLoader et un
SystemClassLoader (&lt;a href=&quot;http://opensource.atlassian.com/confluence/spring/pages/viewpage.action?pageId=2669&quot; hreflang=&quot;en&quot;&gt;en savoir plus&lt;/a&gt;). OSGI (&lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2009/11/26/10-minutes-pour...comprendre-OSGI&quot; hreflang=&quot;en&quot;&gt;voir
l'article publié précédemment&lt;/a&gt;) utilise aussi beaucoup de class loader
différents&lt;/p&gt;
&lt;h3&gt;Explication des menus&lt;/h3&gt;
&lt;p&gt;Lorsque vous cliquez droit sur les objets du dominator tree ou sur les
classes de l'histogramme, vous obtenez un menu vous permettant d'avoir des
informations sur l'élément sélectionné :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List objects=&amp;gt;with outgoing references: objets référencés par l'élément
sélectionné. Si on additionne la taille de ces objets, on obtient la retained
size.&lt;/li&gt;
&lt;li&gt;List objects=&amp;gt;with incomming references : objets qui référencent
l'élément sélectionné.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;
La liste des objets est contextuelle à l'élément sélectionné : si les
objets sont groupés par classe, ou que l'élément est une classe, une ligne par
objet de cette classe sera affichée, si l'élément est un objet, alors seuls les
objets concernés par cet objet (référencé par / qui référence) seront
affichés&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List class =&amp;gt; by outgoing references : les classes des objets
référencés par l'élément.&lt;/li&gt;
&lt;li&gt;List class =&amp;gt; by Incoming references : Les classes des objets qui
ont une référence sur l'élément&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;
La liste des classes affichée est également contextuelle. Exemple pour outgoing
référence : si l'élément sélectionné est une classe, alors la liste de
toutes les classes référencées par tous les objets de cette classe sera listée,
si l'élément est un objet, seule la liste des classes référencées par cet objet
sera affichée.&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Path to GC root =&amp;gt; Affiche les chemins des objets qui référence cet
objet jusqu'à leur élément racine (un peu comme les incomming objects mais
moins en profondeur car s'arrête lorsque l'on arrive au sommet de la pile du
thread auquel appartient l'élément). Il est possible via les sous menus de
filtrer selon les weak / soft / hard références. ce qui peut être utile lorsque
vous utilisez des caches d'objets avec des références soft, car vous pouvez
uniquement inspecter l'élément en tenant compte ou pas du cache. Ce menu n'est
applicable que pour un objet pas pour classe.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Merge Path to GC root : affiche le chemin &lt;strong&gt;le plus
court&lt;/strong&gt; parmi les références racines pour chaque instance de la classe
ou de l'objet sélectionné&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;
Java basics permet d'avoir des renseignements divers sur l'objet (e.g :
chercher une &lt;code&gt;String&lt;/code&gt;). Depuis la version 0.8, il est possible
d'analyser les stacktraces. Ces informations sont disponibles via le menu java
basics=&amp;gt;threads stacks&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java collections sert plus à détecter les gaspillages de mémoire. il permet
par exemple d'avoir le ratio de remplissage d'un tableau.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Leak identification=&amp;gt; Component Report : permet d'avoir des
informations sur la mémoire occupée par cette objet : taille que l'objet
ou que les objets d'une classe occupent dans la pile, leurs &lt;code&gt;soft&lt;/code&gt;
et leurs &lt;code&gt;hard&lt;/code&gt; références,&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Leak identification=&amp;gt; Top consumer : les plus gros éléments
regroupés et triés selon différents critères : Objet, Classe, Class
loader, Package. il permet d'avoir une répartition des objets par classe
(e.g : trouver quels sont les plus gros objets de la classe Salariés). ce
menu est utile lorsque vous l'appliquez sur une classe, car il montre quels
sont les plus gros objets de cette classe et leurs répartitions&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Immediate dominator : Donne les classes des objets qui font que
l'élément est gardé en mémoire (e.g : les immediate dominators de
char&lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/02/05/&quot;&gt;&lt;/a&gt; sont bien souvent des &lt;code&gt;String&lt;/code&gt;). Il est souvent
utile de filtrer les classes des package &lt;code&gt;com.sun.*&lt;/code&gt; et
&lt;code&gt;java.*&lt;/code&gt; car on peut supposer que la fuite ne vienne pas de là. Dans
l'exemple ci dessous, pour les immediate dominator de char&lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/02/05/&quot;&gt;&lt;/a&gt;, si
on considère la ligne concernant &lt;code&gt;Entreprise&lt;/code&gt; : La première
colonne donne le nombre d'objets de la classe listée (1), la deuxième donne le
nombre d'objets référencés par cette classe (3) (un objet Entreprise référence
3 char&lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/02/05/&quot;&gt;&lt;/a&gt; correspondant aux trois commentaires).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.imediate_dominator_m.jpg&quot; alt=&quot;immediate dominator&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;immediate dominator, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Show retained set : donne le nombre d'objets que référence l'élément,
groupés par classe. le retained set représente les objets qui seront libérés si
l'élément est garbage collecté. Pour un objet Entreprise, il contient 3
char&lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/02/05/&quot;&gt;&lt;/a&gt;, 3 Strings et une Entreprise (les trois commentaires+ la
class ). vous pouvez filtrer le retained set par le ou les noms des champs. On
peut alors se demander &amp;quot;Pourquoi les objets &amp;quot;raison social&amp;quot;, &amp;quot;salariés&amp;quot; ne sont
pas dans la retained set alors qu'on les voit si on liste les outgoing objects
de Entreprise. La réponse est que ces objets ne seront pas libérés si
Entreprise disparait. Pour le prouver faites un incomming référence sur les
objet de Entreprise : les commentaires ne sont uniquement référencés par
Entreprise, alors que raison social par exemple est également référencé comme
clé pour la &lt;code&gt;Hashmap&lt;/code&gt; de &lt;code&gt;cacheEntreprise&lt;/code&gt;. De même pour
&amp;quot;raison social&amp;quot; qui est une constante car déclarée dans le code, alors que les
3 commentaires sont générés au runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Savoir lire les graphes&lt;/h3&gt;
&lt;p&gt;Lorsque l'on est devant un graphe, il est important de savoir le lire.
prenons l'exemple pour des 'outgoing références' :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.outgoing_m.jpg&quot; alt=&quot;outgoing&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;outgoing, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;La classe Entreprise à des référence vers 4 objets de type String qui se
nomme 'commentaire', 'commentaire2', commentaire3, et 'raison social'. et une
ArrayList qui se nome salarié. si l'un des objet avait une valeur null, il
n'aurait pas été listé.&lt;/p&gt;
&lt;p&gt;Voyons maintenant comment lire des 'incoming références' :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.incoming_m.jpg&quot; alt=&quot;incoming&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;incoming, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;L'objet entreprise (je dis bien objet et pas classe) est référencé
par :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le champs 'entreprise' de 3 objets de type Salarié,&lt;/li&gt;
&lt;li&gt;Le thread lui même , correspondant à la déclaration de la variable
(Entreprise entreprise = new Entreprise() )&lt;/li&gt;
&lt;li&gt;Le champs 'value' d'une HashMap, correspondant à la &lt;code&gt;HashMap&lt;/code&gt; de
cache nommée entreprise et appartenant à la classe CacheEntreprise .&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lorsque l'on analyse des dumps mémoire, il est fortement conseillé de
connaitre la représentation interne des objets &lt;code&gt;Map&lt;/code&gt;,
&lt;code&gt;Collections&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, etc. Cela permet de mieux
naviguer. Une &lt;code&gt;HashMap&lt;/code&gt; est par exemple constitué d'un tableau de
hashMapEntry, lui même constitué de champs key, value, et hash. Si vous voulez
explorer un objet, allez sur l'onglet 'attributes', cliquez droit, puis
sélectionnez 'Go into' :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.attribut_m.jpg&quot; alt=&quot;attribut&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;attribut, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Les rapports de fuites mémoires&lt;/h3&gt;
&lt;p&gt;Entrons maintenant dans le vif du sujet. Le rapport proposant des
responsables des fuites mémoires. Comment cela fonctionne ? En fait
l'outil analyse le dump et recherche les 'Leak suspects', Il commence par
chercher les points d'accumulation en analysant les écarts significatifs dans
la retained size entre deux objets du graphe, puis remonte les 'incomming
references', prend le plus court chemin, et en déduit le suspect.&lt;/p&gt;
&lt;p&gt;Un rapport HTML comprenant plusieurs sections est alors généré :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;les points d'accumulation : donnent les informations sur la taille et
le type d'objets, le thread incriminé, et le nombre d'objets contenus.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le rapport génère aussi une liste de mots clés permettant de le googliser ou
de les taper dans un bug tracker. L'idée est à mon sens excellente :
Lorsque vous créez le bug, vous y ajoutez ces mots clés, et une personne qui
désire retrouver ce bug ou voir si une résolution a déjà été trouvée, tape ces
mots clés, retrouve le bug et une potentielle résolution éprouvée.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.leak_report_m.jpg&quot; alt=&quot;leak report&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;leak report, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Deux questions se posent alors :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Qui garde une référence à cet objet ?&lt;/li&gt;
&lt;li&gt;Pourquoi l'objet est si gros et que contient il ?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pour la première question on va chercher quel est le plus court chemin du GC
root jusqu'à l'objet du point d'accumulation :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.leak_report_shortest_path_m.jpg&quot; alt=&quot;leak report shortest path&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;leak report shortest path, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Le graphe ce lit 'ligne du haut' est contenu par 'ligne du dessous'. Dans
l'exemple ci dessus : le tableau d'objet est référencé par le thread
(Chemin le plus court) et par une &lt;code&gt;ArrayList&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Pour la deuxième question MAT nous donne un aperçu des objets référencés par
le point d'accumulation. Cela permet en général d'avoir une idée plus précise
de la cause de la fuite.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.leak_report_accumulated_object_m.jpg&quot; alt=&quot;leak report accumulated object&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;leak report accumulated object, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Le rapport fournit également une répartition des objets référencé par le
point d'accumulation par classes. Dans notre cas, le tableau d'objet ne
contient que des &lt;code&gt;Double&lt;/code&gt;, ce qui laisse à penser qu'une méthode
remplit le tableau.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.leak_suspect_byclass_m.jpg&quot; alt=&quot;leak suspect by class&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;leak suspect by class, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Une autre information intéressante est l'environnement d'exécution. Dans
quel contexte a eu lieu le dump. Cela à une importance quand vous utilisez
&lt;code&gt;-XX:HeapDumpOnOutOfMemoryError&lt;/code&gt; . Les informations importantes sont
entre autres :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Les propriétés de la JVM (Xms, Xmx). Peut être un mauvais dimensionnement
de la mémoire ?&lt;/li&gt;
&lt;li&gt;Le nombre de threads et leurs tailles permettent de voir si un seul thread
est incriminé, et dans ce cas, selon la nature de traitement qu'à le thread,
vous pouvez plus cibler la fuite (exemple : un thread de purge d'un
cache)&lt;/li&gt;
&lt;li&gt;L'histogramme des classes peut également donner des informations sur la
cause. S'il existe un grand nombre d'objets appartenant à un classe d'un de vos
package, il est probable (pas à 100%, mais vous disposez déjà d'une piste) que
la fuite est causée par du code vous appartenant.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Informations sur les threads&lt;/h3&gt;
&lt;p&gt;MAT fournit des informations sur le context d'exécution des threads. il
inspecte les variables &lt;code&gt;threadLocal&lt;/code&gt; et selon ce qu'il y trouve,
nous donne des informations supplémentaires. exemple :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;s'il trouve des objets sur des requêtes HTTP il inspectera l'objet et en
extraira les headers, URL, status code, etc.&lt;/li&gt;
&lt;li&gt;s'il trouve des connections JDBC, il extraira les resultsets, query,...on
peut par exemple voir qu'il manque un clause &lt;code&gt;where&lt;/code&gt;, ce qui fait
que beaucoup trop d'objets sont rapatriés, et cause une trop grande
consommation mémoire&lt;/li&gt;
&lt;li&gt;s'il trouve des contexts OSGI, il explorera leurs contenus.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voici deux exemples : le premier pour un thread exécutant une requête
SQL :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.thread_sql_m.jpg&quot; alt=&quot;thread sql&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;thread sql, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;
le deuxième pour un thread exécutant une requête soap :&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/memoryleak/.thread_soap_m.jpg&quot; alt=&quot;thread soap&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;thread soap, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;On peut légitimement se poser la question &amp;quot;comment sont déterminer ces
informations ? &amp;quot; en fait si le suspect est un thread, il explore son nom
(exemple &amp;quot;HTTP-processor&amp;quot; pour un thread Tomcat, &amp;quot;RMI TCP
Connection(8)-127.0.0.1 pour un connecteur jmx, &amp;quot;Timer-3&amp;quot; pour un
&lt;code&gt;timerThread&lt;/code&gt;), il inspecte les variables &lt;code&gt;threadLocal&lt;/code&gt;
et selon ce qu'il y trouve nous donne des informations supplémentaires. Ce
système d'exploration est basé sur un système de plugins, vous pouvez donc en
créer vous même selon vos besoins&lt;/p&gt;
&lt;h3&gt;OQL ou Object Query Language&lt;/h3&gt;
&lt;p&gt;Pour permetre de rechercher des objets facilement, vous pouvez les
rechercher avec une syntaxe SQL like. Exemple :&lt;/p&gt;
&lt;pre&gt;
select e.nom from com.demo.mat.Entreprise e
&lt;/pre&gt;
&lt;p&gt;Vous pouvez utiliser des clauses WHERE, des UNION, des projections (avg,
min, max,...). vraiment très pratique pour trouver, compter, avoir des
statistiques sur des objets en particulier. (&lt;a href=&quot;http://en.wikipedia.org/wiki/Object_Query_Language&quot; hreflang=&quot;en&quot;&gt;en savoir
plus&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Voilà pour la théorie :) j'espère que vous maitrisez les différents concepts
de l'outil et que vous savez désormais aller chercher les informations
pertinentes.&lt;/p&gt;
&lt;p&gt;Le prochain post sera basé sur un cas concret et expliquera comment j'ai
résolu une fuite mémoire sur Gisgraphy, en 15 minutes à l'aide de MAT.&lt;/p&gt;</description>
    
          <enclosure url="http://davidmasclet.gisgraphy.com/public/memoryleak/memory_leak_exemple.zip"
      length="2977" type="application/zip" />
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/02/05/D%C3%A9tecter-et-corriger-les-fuites-m%C3%A9moire-java#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/02/05/D%C3%A9tecter-et-corriger-les-fuites-m%C3%A9moire-java#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/482002</wfw:commentRss>
      </item>
    
  <item>
    <title>Nouveau look aux idées larges !</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/02/27/nouveau-look-aux-id%C3%A9es-larges</link>
    <guid isPermaLink="false">urn:md5:ade6e2b91458fa0adcd0dbfee3449a86</guid>
    <pubDate>Sat, 27 Feb 2010 15:56:00 +0100</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Divers</category>
            
    <description>    &lt;p&gt;Le blog à désormais un nouveau look. oh... pas très très différent. Je suis
juste partie du thème précédent et j'ai changé le style pour l'adapter aux
styles des billets : c'est-à-dire des articles techniques.&lt;br /&gt;
&lt;br /&gt;
En effet en regardant les statistiques des résolutions d'écran des
utilisateurs, J'ai remarqué que personne n'était en 800*600, alors que le thème
était optimisé pour une résolution 800*600. J'ai donc augmenté la largeur de la
colonne centrale en diminuant les marges de chaque coté, attribué plus de place
à la colonne de contenu, et diminué la colonne avec les rubriques, qui me
semblait moins importantes que le contenu. A mon sens, le texte est beaucoup
plus lisible. Pour les zone de code, j'ai également opté pour une couleur
jaune, plus sympathique que le gris. Faites moi part de vos impressions, et des
éventuels problèmes rencontrés.&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/02/27/nouveau-look-aux-id%C3%A9es-larges#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/02/27/nouveau-look-aux-id%C3%A9es-larges#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/490478</wfw:commentRss>
      </item>
    
  <item>
    <title>Tester du code en ligne</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/02/04/Tester-du-code-en-ligne</link>
    <guid isPermaLink="false">urn:md5:af837b1c49a518630a71db5e6c4150dc</guid>
    <pubDate>Thu, 04 Feb 2010 15:35:00 +0100</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Divers</category>
        <category>javascript</category>    
    <description>    &lt;p&gt;Certains connaissent peut être &lt;a href=&quot;http://pastebin.com/&quot; hreflang=&quot;en&quot;&gt;pastebin&lt;/a&gt; qui permet d'envoyer du code à quelqu'un (ou d'un PC à
l'autre ;) ) en générant une shortURL. Il existe des sites qui vont plus loin
en permettant de tester du code directement en ligne : &lt;a href=&quot;http://codepad.org/&quot; hreflang=&quot;en&quot;&gt;http://codepad.org/&lt;/a&gt;. il suffit de
copier / coller votre code, et le site vous le compile et vous l'interprète.
c'est le cas de &lt;a href=&quot;http://codepad.org/&quot; hreflang=&quot;en&quot;&gt;codepad&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/.codepad_m.jpg&quot; alt=&quot;codepad&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;codepad, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Il supporte les langages suivants :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C&lt;/li&gt;
&lt;li&gt;C++&lt;/li&gt;
&lt;li&gt;D&lt;/li&gt;
&lt;li&gt;Haskell&lt;/li&gt;
&lt;li&gt;Lua&lt;/li&gt;
&lt;li&gt;OCaml&lt;/li&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;Perl&lt;/li&gt;
&lt;li&gt;Plain Text&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;Scheme&lt;/li&gt;
&lt;li&gt;Tcl&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Vous pouvez mettre votre code &amp;quot;privé&amp;quot;, ce qui est pratique, car j'ai déjà
retrouvé du code, que je ne voulais pas partager publiquement, indexé par
Google, après l'avoir envoyé via pastebin)&lt;/p&gt;
&lt;p&gt;Dans la même lignée, il existe des sites plus spécialisés pour tester les
interactions HTML&amp;lt;=&amp;gt;Javascript : &lt;a href=&quot;http://jsbin.com/&quot; hreflang=&quot;en&quot;&gt;http://jsbin.com/&lt;/a&gt;. Son utilisation est triviale : vous
avez le code javascript à gauche et le code HTML à droite.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/.jsbin_m.jpg&quot; alt=&quot;jsbin&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;jsbin, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Le site va beaucoup plus loin que pastebin, d'une part, car il est
spécialisé dans un langage, mais aussi parce qu' il offre la
possibilité :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;De sauvegarder votre code.&lt;/li&gt;
&lt;li&gt;D'inclure des librairies connues, comme Prototype, Jquery, Mootools, Dojo
et de choisir parmi différentes versions&lt;/li&gt;
&lt;li&gt;De générer une short URL de votre code (exemple :
http://jsbin.com/ilomu3)&lt;/li&gt;
&lt;li&gt;De modifier un code existant en cliquant sur ''Edit using JS Bin&amp;quot; en haut à
droite (j'avoue c'est pas flagrant :) ).&lt;/li&gt;
&lt;li&gt;De gérer plusieurs versions d'un même code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L'avantage est qu'il permet de tester du code avant de mettre à jour un
librairie (exemple : passer de Prototype 1.6.03 à 1.6.1.0), de vous faire
la main sur des librairies, ou de partager du code entre collègues.&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/02/04/Tester-du-code-en-ligne#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/02/04/Tester-du-code-en-ligne#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/481779</wfw:commentRss>
      </item>
    
  <item>
    <title>iPad nano</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/02/01/iPad-nano</link>
    <guid isPermaLink="false">urn:md5:a21b270de4a84d0e36befc39217543cd</guid>
    <pubDate>Mon, 01 Feb 2010 11:25:00 +0100</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>humour</category>
        <category>Apple</category><category>Humour</category><category>Ipad</category>    
    <description>    &lt;p&gt;Pour faire suite à mon post &lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/01/04/Strat%C3%A9gie-d-Apple-vs-strat%C3%A9gie-Google&quot;&gt;Stratégie
d'Apple vs stratégie Google&lt;/a&gt;, je vous propose une image qui m'a fait bien
rire&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://davidmasclet.gisgraphy.com/public/.ipadnano_m.jpg&quot; alt=&quot;ipadnano&quot; style=&quot;display:block; margin:0 auto;&quot; title=&quot;ipadnano, fév. 2010&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sinon, je vous conseille la lecture de ce &lt;a href=&quot;http://www.presse-citron.net/ipad-si-jetais-apple-je-minquieterais&quot;&gt;billet&lt;/a&gt;
sur l'ipad et son effet d'annonce manqué&lt;/p&gt;</description>
    
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/02/01/iPad-nano#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/02/01/iPad-nano#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/480921</wfw:commentRss>
      </item>
    
  <item>
    <title>Tester le javascript : JSUnit, JSmock, Jstester (partie 2)</title>
    <link>http://davidmasclet.gisgraphy.com/post/2010/01/26/Tester-le-javascript-%3A-JSUnit%2C-JSmock%2C-Jstester-%28partie-2%29</link>
    <guid isPermaLink="false">urn:md5:cb80e7b4d3cc6bce000ad3004d406279</guid>
    <pubDate>Tue, 26 Jan 2010 13:16:00 +0100</pubDate>
    <dc:creator>Masclet</dc:creator>
        <category>Tests / XUnit</category>
        <category>Javascript</category><category>JsMock</category><category>JsUnit</category><category>test</category>    
    <description>&lt;p&gt;Après le &lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/01/08/Tester-le-javascript-%3A-JSUnit%2C-JSmock%2C-Jstester-%28partie-1%29&quot;&gt;
billet&lt;/a&gt; consacré à JsUnit et &lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2009/03/13/Mock-ajax-request&quot;&gt;celui&lt;/a&gt; qui expliquait comment mocker
une requête Ajax, nous allons maintenant voir comment mocker en javascript.
Pour cela je vous propose une courte présentation de JsMock. Les exemples de
code sont en annexe de ce billet.&lt;/p&gt;    &lt;p&gt;Pour montrer les capacités de JsMock, rien de tel que des exemples de code.
Nous allons donc reprendre le code du &lt;a href=&quot;http://davidmasclet.gisgraphy.com/post/2010/01/08/Tester-le-javascript-%3A-JSUnit%2C-JSmock%2C-Jstester-%28partie-1%29&quot;&gt;
premier billet&lt;/a&gt; (vous pouvez télécharger les sources en annexe du premier
billet)&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;La première chose à faire est de télécharger &lt;a href=&quot;http://jsmock.sourceforge.net/&quot; hreflang=&quot;en&quot;&gt;JsMock&lt;/a&gt; et de l'ajouter dans
le répertoire JsUnit (ou ailleurs, mais le tout est d'être cohérent lors de la
déclaration dans le fichier HTML) , puis de l'importer à partir de notre
fichier de tests &lt;code&gt;SimpleCodeTest&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
&amp;lt;script language=&amp;quot;JavaScript&amp;quot; type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;../jsmock.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;Exemple de code à mocker&lt;/h3&gt;
&lt;p&gt;Pour comprendre les mocks il vaux mieux faire interagir deux objets entre
eux : cela permet de tester un objet et d'en mocker un autre. Ajoutons
donc un objet &lt;code&gt;ConfigParameter&lt;/code&gt; et définissons en une instance dans
MyObjectToTest :&lt;/p&gt;
&lt;pre&gt;
function ConfigParameter() {
        this.getAlertMessage = function(){
                return &amp;quot;alertMessage&amp;quot;;
        }

        this.setParam = function(Aname, Avalue) {
                //this[name]=value
        }
}

function MyObjectToTest(){
        this.configParameter = new ConfigParameter();

        var message = &amp;quot;Not defined yet!&amp;quot;;
        
        this.setMessage = function(messageParam){
                message = messageParam
        }

        this.getMessage = function(){
                return message;
        }

        this.getAlertMessage = function(){
               return this.configParameter.getAlertMessage();
        }

        this.setConfigValue = function(){
                this.configParameter.setParam(&amp;quot;MyName&amp;quot;, &amp;quot;MyValue&amp;quot;);
        }

}
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;Mocker des valeurs de retour&lt;/h3&gt;
&lt;p&gt;Voici un exemple où nous allons mocker le retour de
&lt;code&gt;getAlertMessage&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
function testMockReturnedValue() {
        // Actor
        MyObj = new MyObjectToTest();
        
        // Mock
        mockControl = new MockControl();
        mockConfig = mockControl.createMock(ConfigParameter);
        mockConfig.expects().getAlertMessage().andReturn(&amp;quot;mock Alert Message&amp;quot;);

        MyObj.configParameter = mockConfig;

        // Assert
        assertEquals(&amp;quot;mock Alert Message&amp;quot;, MyObj.getAlertMessage());
        
        mockControl.verify();
}

&lt;/pre&gt;
&lt;p&gt;Vous remarquerez qu'à la différence de EasyMock en Java, il n'est pas
nécessaire d'appeler la méthode &lt;code&gt;replay()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;La méthode &lt;code&gt;vérify&lt;/code&gt; permet de vérifier que les méthodes mockées
sont bien appelées le bon nombre de fois : si une méthode non défini par
votre mock est appelée le test ne passera pas, en revanche vous pourriez avoir
défini le comportement d'une méthode mais que cette dernière ne soit jamais
appelée, dans ce cas, si vous n'appelez pas la méthode &lt;code&gt;verify&lt;/code&gt;, le
test passera mais vous ne saurez pas que la méthode n'a pas été appelée).&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;mocker des fonctions&lt;/h3&gt;
&lt;p&gt;Il est possible de simuler les comportement (le corps de la méthode) d'une
fonction grâce à la méthode &lt;code&gt;andStub&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
function testStubFunction() {
        // Actor
        MyObj = new MyObjectToTest();
        
        // Mock
        mockControl = new MockControl();
        mockConfig = mockControl.createMock(ConfigParameter);
        mockConfig.expects().getAlertMessage().andStub(
                 function() { 
                        return &amp;quot;test&amp;quot;;
                 } 
        );

        MyObj.configParameter = mockConfig;

        // Assert
        assertEquals(&amp;quot;test&amp;quot;, MyObj.getAlertMessage());
}
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;Simuler des exceptions&lt;/h3&gt;
&lt;p&gt;Il est également possible de simuler des exceptions avec la méthode
&lt;code&gt;andThrow&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;
function testThrow() {
        exception = false ;
        // Actor
        MyObj = new MyObjectToTest();
        
        // Mock
        mockControl = new MockControl();
        mockConfig = mockControl.createMock(ConfigParameter);
        mockConfig.expects().getAlertMessage().andThrow(&amp;quot;Error !&amp;quot;);

        MyObj.configParameter = mockConfig;

        try {   
        MyObj.getAlertMessage();
        } catch (e){
          exception = true;
        }

        assertEquals(true, exception);
}
&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h3&gt;Mocker des fonctions avec paramètres&lt;/h3&gt;
&lt;p&gt;Pour mocker une fonction avec des paramètres, vous avez deux
possibilités : soit vous spécifiez le type des paramètres lors de la
définition du mock, dans le cas où seul le type des paramètres vous importe.
Pour cela utiliser &lt;code&gt;TypeOf.isA()&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;
function testFunctionWithTypedParameters() {
        // Actor
        MyObj = new MyObjectToTest();
        
        // Mock
        mockControl = new MockControl();
        mockConfig = mockControl.createMock(ConfigParameter);
        mockConfig.expects().setParam(TypeOf.isA(String),TypeOf.isA(String));

        MyObj.configParameter = mockConfig;


        MyObj.setConfigValue();

        mockControl.verify();
}
&lt;/pre&gt;
&lt;p&gt;soit vous spécifiez la valeur des paramètres, si vous voulez vérifier que la
fonction est appelée avec les bonnes valeurs :&lt;/p&gt;
&lt;pre&gt;
function testFunctionWithParameters() {
        // Actor
        MyObj = new MyObjectToTest();
        
        // Mock
        mockControl = new MockControl();
        
        mockConfig = mockControl.createMock(ConfigParameter);
        mockConfig.expects().setParam(&amp;quot;MyName&amp;quot;, &amp;quot;MyValue&amp;quot;);

        MyObj.configParameter = mockConfig;
        MyObj.setConfigValue();

        mockControl.verify();
}

&lt;/pre&gt;
&lt;p&gt;J'espère que cela vous à donner envie de l'utiliser, car le Javascript est
de plus en plus présent dans les applications web et les tests permettent de
mieux découpler votre code et de le rendre plus robuste.&lt;/p&gt;
&lt;p&gt;La troisième et dernière partie traitera de &lt;code&gt;JsTester&lt;/code&gt; qui permet
de tester du javascript coté serveur (JsUnit dispose d'une partie serveur mais
elle n'est là que pour piloter les tests, il faut toujours avoir un
navigateur). nous verrons ses avantages et ses inconvénients et comment
l'intégrer avec Maven et JUnit.&lt;/p&gt;</description>
    
          <enclosure url="http://davidmasclet.gisgraphy.com/public/jsmock.zip"
      length="2959" type="application/zip" />
    
    
          <comments>http://davidmasclet.gisgraphy.com/post/2010/01/26/Tester-le-javascript-%3A-JSUnit%2C-JSmock%2C-Jstester-%28partie-2%29#comment-form</comments>
      <wfw:comment>http://davidmasclet.gisgraphy.com/post/2010/01/26/Tester-le-javascript-%3A-JSUnit%2C-JSmock%2C-Jstester-%28partie-2%29#comment-form</wfw:comment>
      <wfw:commentRss>http://davidmasclet.gisgraphy.com/feed/atom/comments/479006</wfw:commentRss>
      </item>
    
</channel>
</rss>
