diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..091699910865adf043ee14c299e4b6ffcf2817d8
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <!-- ************************************************************* -->
+    <!-- *** POM Relationships *************************************** -->
+    <!-- ************************************************************* -->
+
+    <groupId>fr.cemagref</groupId>
+    <artifactId>observation</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+            <version>1.3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>jfree</groupId>
+            <artifactId>jfreechart</artifactId>
+            <version>1.0.13</version>
+        </dependency>
+        <dependency>
+            <groupId>fr.cemagref</groupId>
+            <artifactId>ohoui</artifactId>
+            <version>0.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>jfree</groupId>
+            <artifactId>jcommon</artifactId>
+            <version>1.0.15</version>
+        </dependency>
+    </dependencies>
+
+    <!-- ************************************************************* -->
+    <!-- *** Project Information ************************************* -->
+    <!-- ************************************************************* -->
+
+    <name>${project.artifactId} ${project.version}</name>
+    <description></description>
+    <url>http://trac.clermont.cemagref.fr/projets/LISC/wiki/JavaObservation</url>
+
+    <licenses>
+        <license>
+            <name>GPL</name>
+            <url>http://www.gnu.org/copyleft/gpl.html</url>
+            <distribution>repo</distribution>
+        </license>
+    </licenses>
+
+    <!-- ************************************************************* -->
+    <!-- *** Build Settings ****************************************** -->
+    <!-- ************************************************************* -->
+
+    <packaging>jar</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <configuration>
+                    <overWriteReleases>false</overWriteReleases>
+                    <overWriteSnapshots>false</overWriteSnapshots>
+                    <overWriteIfNewer>true</overWriteIfNewer>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <distributionManagement>
+        <repository>
+            <id>trac.clermont.cemagref.fr.nexus</id>
+            <url>http://trac.clermont.cemagref.fr/nexus/content/repositories/releases</url>
+        </repository>
+        <snapshotRepository>
+            <id>trac.clermont.cemagref.fr.nexus</id>
+            <url>http://trac.clermont.cemagref.fr/nexus/content/repositories/snapshots</url>
+        </snapshotRepository>
+    </distributionManagement>
+
+</project>
+
+
+
diff --git a/src/main/java/fr/cemagref/observation/gui/Configurable.java b/src/main/java/fr/cemagref/observation/gui/Configurable.java
new file mode 100644
index 0000000000000000000000000000000000000000..0db2c6c22e4f28e0e6df036f32e8a6dbe419c3da
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/gui/Configurable.java
@@ -0,0 +1,14 @@
+package fr.cemagref.observation.gui;
+
+
+/**
+ * <code>Configurable</code> This interface is implemented by GUI element that are configurables. (element in a list, panel, ...)
+ */
+public interface Configurable {
+    
+    /**
+     * <code>configure</code> is called when the user want to configure the component.
+     *
+     */
+    public void configure();
+}
diff --git a/src/main/java/fr/cemagref/observation/gui/ControlsFactory.java b/src/main/java/fr/cemagref/observation/gui/ControlsFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..7ab793938eaf74162bee2f664b9a5a0950038ef4
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/gui/ControlsFactory.java
@@ -0,0 +1,36 @@
+package fr.cemagref.observation.gui;
+
+import java.awt.event.ActionListener;
+import java.net.URL;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+
+public class ControlsFactory {
+    
+    public static JButton makeButton(String imageName,
+            ActionListener listener,
+            String toolTipText,
+            String altText) {
+        // Look for the image.
+        String imgLocation = "toolbarButtonGraphics/"
+            + imageName
+            + ".gif";
+        URL imageURL = ControlsFactory.class.getClassLoader().getResource(imgLocation);
+        // Create and initialize the button.
+        JButton button = new JButton();
+        button.setToolTipText(toolTipText);
+        button.addActionListener(listener);
+        if (imageURL != null) {
+            //image found
+            button.setIcon(new ImageIcon(imageURL, altText));
+        } else {
+            //no image found
+            button.setText(altText);
+            System.err.println("Resource not found: " + imgLocation);
+        }
+        
+        return button;
+    }
+    
+}
diff --git a/src/main/java/fr/cemagref/observation/gui/Drawable.java b/src/main/java/fr/cemagref/observation/gui/Drawable.java
new file mode 100644
index 0000000000000000000000000000000000000000..02bf58ede4253925ad7c13faff81f53cc4179121
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/gui/Drawable.java
@@ -0,0 +1,18 @@
+package fr.cemagref.observation.gui;
+
+import javax.swing.JComponent;
+
+/**
+ * <code>Drawable</code> A component implements this interface if it could be graphically drawed as a JComponent.
+ */
+public interface Drawable {
+    
+    /**
+     * <code>getTitle</code>
+     *
+     * @return The title of this component.
+     */
+    public String getTitle();
+    
+    public JComponent getDisplay();
+}
diff --git a/src/main/java/fr/cemagref/observation/gui/ObserversManagerHandler.java b/src/main/java/fr/cemagref/observation/gui/ObserversManagerHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..26e9cd25d64801a49745ec0411c958d7bf7155e7
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/gui/ObserversManagerHandler.java
@@ -0,0 +1,15 @@
+package fr.cemagref.observation.gui;
+
+import javax.swing.JFrame;
+
+/**
+ * <code>ObserversManagerHandler</code> is those who handles the ObservableManager.
+ */
+public interface ObserversManagerHandler {
+    /**
+     * <code>getHandlingFrame</code> is used by dialog box to know which is the parent frame. 
+     */
+    public JFrame getHandlingFrame();
+
+    public void showDrawable(Drawable drawable);
+}
diff --git a/src/main/java/fr/cemagref/observation/gui/ObserversManagerPanel.java b/src/main/java/fr/cemagref/observation/gui/ObserversManagerPanel.java
new file mode 100644
index 0000000000000000000000000000000000000000..5ab47c2ede5d9f3390e7cac2722f5c3adfe658dd
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/gui/ObserversManagerPanel.java
@@ -0,0 +1,111 @@
+package fr.cemagref.observation.gui;
+
+import fr.cemagref.observation.kernel.ObservableManager;
+import fr.cemagref.observation.kernel.ObservableManager.ClassAndObserver;
+
+import java.awt.BorderLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.HashSet;
+
+import javax.swing.JButton;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JToolBar;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+@SuppressWarnings("serial")
+public class ObserversManagerPanel extends JPanel implements ListSelectionListener {
+
+    private ObserversManagerHandler observersManagerHandler;
+    private JList list;
+    private JButton removeButton;
+    private JButton confButton;
+    private JButton showButton;
+   
+    private HashSet<ClassAndObserver> observersShowed = new HashSet<ClassAndObserver>();
+    
+    public ObserversManagerPanel(ObserversManagerHandler observersManagerHandler) {
+        super();
+        this.observersManagerHandler = observersManagerHandler;
+        
+        this.setLayout(new BorderLayout());
+        // The list
+        list = new JList(ObservableManager.getObservableManager());
+        list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+        list.setLayoutOrientation(JList.HORIZONTAL_WRAP);
+        list.addListSelectionListener(this);
+        JScrollPane listScroller = new JScrollPane(list);
+        this.add(listScroller,BorderLayout.CENTER);
+        
+        // The toolbar
+        JToolBar toolBar = new JToolBar();
+        toolBar.setFloatable(false);
+        add(toolBar,BorderLayout.PAGE_END);
+
+        // The "remove" button
+        removeButton = ControlsFactory.makeButton("general/Delete24",new RemoveButtonListener(),"Remove the selected module","Remove");        
+        toolBar.add(removeButton);
+        
+        // The "conf" button
+        confButton = ControlsFactory.makeButton("general/Edit24",new ConfButtonListener(),"Configure the selected module","Configure");        
+        toolBar.add(confButton);
+
+        // The "show" button
+        showButton = ControlsFactory.makeButton("general/Find24",new ShowButtonListener(),"Show the selected module","Show");        
+        toolBar.add(showButton);
+
+        // set buttons enabled or not
+        this.valueChanged(null);
+    }
+
+    public void valueChanged(ListSelectionEvent e) {
+        if (list.getSelectedIndex()>=0) {
+            ClassAndObserver classAndObserver = (ClassAndObserver)list.getSelectedValue();
+            removeButton.setEnabled(true);
+            confButton.setEnabled(classAndObserver.getObserver() instanceof Configurable);
+            showButton.setEnabled(
+                    // observers must be drawable
+                    classAndObserver.getObserver() instanceof Drawable
+                    // and observers must not be yet displayed
+                    && !observersShowed.contains(classAndObserver)
+            );
+        } else {
+            removeButton.setEnabled(false);
+            confButton.setEnabled(false);
+            showButton.setEnabled(false);
+        }
+        
+    }
+
+    private class RemoveButtonListener implements ActionListener {
+        public void actionPerformed(ActionEvent e) {
+            if (JOptionPane.showConfirmDialog(observersManagerHandler.getHandlingFrame(),"Sure ?","Confirmation",JOptionPane.YES_NO_OPTION)==0) {
+                ClassAndObserver item = (ClassAndObserver)list.getSelectedValue();
+                ObservableManager.removeObserverListener(item.getType(),item.getObserver());
+            }
+        }
+    }
+
+    private class ConfButtonListener implements ActionListener {
+        public void actionPerformed(ActionEvent e) {
+            ((Configurable)((ClassAndObserver)list.getSelectedValue()).getObserver()).configure();
+        }
+    }
+    
+    private class ShowButtonListener implements ActionListener {
+        public void actionPerformed(ActionEvent e) {
+            ClassAndObserver classAndObserver = (ClassAndObserver)list.getSelectedValue();
+            if (observersShowed.add(classAndObserver)) {
+                // force buttons enabling refresh
+                valueChanged(null);
+                // get display and add it in handler
+                observersManagerHandler.showDrawable((Drawable)classAndObserver.getObserver());
+            }
+        }
+    }
+}
diff --git a/src/main/java/fr/cemagref/observation/kernel/Observable.java b/src/main/java/fr/cemagref/observation/kernel/Observable.java
new file mode 100644
index 0000000000000000000000000000000000000000..c87ab68a61d39ac7ae29899e5cbe2d74b1e4ec03
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/kernel/Observable.java
@@ -0,0 +1,22 @@
+/**
+ *  L'interface "annotation" pour marquer les observables.
+ */
+package fr.cemagref.observation.kernel;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * <code>Observable</code> The annotation used to declare a field as observable
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+public @interface Observable {
+    /**
+     * <code>description</code> is the textual description of the observable.
+     *
+     * @return the textual description of the observable.
+     */
+    String description();
+}
diff --git a/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java b/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..76cb0b3ee3a285c7aa6f02ca1ef8c6fc4c4434bb
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/kernel/ObservableManager.java
@@ -0,0 +1,237 @@
+package fr.cemagref.observation.kernel;
+
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.ListModel;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+
+/**
+ * TODO traduce in english
+ */
+public class ObservableManager implements ListModel {
+
+    private static ObservableManager om = null;
+    private Map<Class, ObservablesHandler> observables;
+    private List<ListDataListener> listDataListeners = new ArrayList<ListDataListener>();
+
+    /** Le constructeur. Il est private, car l'accès à l'observable manager doit
+     * se faire exclusivement via la méthode statique getObservableManager().
+     */
+    private ObservableManager() {
+		observables = new Hashtable<Class,ObservablesHandler>();
+    }
+
+    /**
+     * The true mean to access Observable manager.
+     *
+     * @return L'observable manager du système.
+     */
+    public static ObservableManager getObservableManager() {
+        return om == null ? om = new ObservableManager() : om;
+    }
+
+    /**
+     * clear method clears all class-observers associations
+     */
+    public static void clear() {
+        for (ObservablesHandler co : om.observables.values()) {
+            co.clearObservers();
+        }
+        om.fireObservableManagerStructureChanged();
+    }
+
+    /**
+     * Déclare une classe comme étant observable.
+     *
+     * Si une classe a déjà été déclarée comme observable,
+     * l'appel de cette méthode est équvalent à un getObservable(Class).
+     *
+     * @param cl La classe déclarée comme observable
+     * @return Le ClassObservable de cl.
+     */
+    public static ObservablesHandler addObservable(Class cl) {
+        if (getObservableManager().observables.containsKey(cl)) {
+            return getObservableManager().observables.get(cl);
+        }
+        ObservablesHandler co = new ObservablesHandler(cl);
+        getObservableManager().observables.put(cl, co);
+        getObservableManager().fireObservableManagerStructureChanged();
+        return co;
+    }
+
+    /** Permet d'obtenir l'instance de ClassObservable associée à la classe
+     * donnée en argument.
+     *
+     * PERFS : Les classObservable sont stockées dans une Hashtable,
+     * avec une clé sur Class, c'est à dire que l'algo est de l'ordre
+     * de N log(N) (où N est le nombre d'observables), avec
+     * (ce qui n'est pas négligeable), une opération de base qui est Class.equals(Object).
+     * En conclusion : pour une utilisation très intensive, on gardera une variable
+     * pointant sur le ClassObservable, pour éviter d'appeler trop souvent cette méthode.
+     *
+     * @param cl La classe dont on veut le ClassObservable
+     * @return Le classObservable, ou null si la classe donnée en argument
+     * n'a pas été déclarée comme étant observable.
+     */
+    public static ObservablesHandler getObservable(Class cl) {
+        return getObservableManager().observables.get(cl);
+    }
+
+    /** Ajoute un ObserverListener à la liste.
+     * 
+     * @param ob L'ObserverListener à ajouter.
+     */
+    public static ObserverListener addObserverListener(Class cl, ObserverListener ob) {
+        ObserverListener observerListener = addObservable(cl).addObserverListener(ob);
+        getObservableManager().fireObservableManagerStructureChanged();
+        return observerListener;
+    }
+
+    /** Retire un seul observerListener de la liste. Renvoie true s'il a effectivement été trouvé
+     * et retiré.
+     * @param ob L'ObserverListener à retirer. 
+     * @return
+     */
+    public static boolean removeObserverListener(Class cl, ObserverListener ob) {
+        boolean response = getObservable(cl).removeObserverListener(ob);
+        getObservableManager().fireObservableManagerStructureChanged();
+        return response;
+    }
+
+    public static void initObservers() {
+        for (ObservablesHandler classObservable : getObservableManager().observables.values()) {
+            for (ObserverListener observer : classObservable.getObservers()) {
+                observer.init();
+            }
+        }
+    }
+
+    public static void closeObservers() {
+        for (ObservablesHandler classObservable : getObservables().values()) {
+            for (ObserverListener observer : classObservable.getObservers()) {
+                observer.close();
+            }
+        }
+    }
+
+    public static Map<Class, ObservablesHandler> getObservables() {
+        return getObservableManager().observables;
+    }
+
+    public static void setObservers(Reader observablesReader, XStream xstream) {
+        Map<Class,ObservablesHandler> observablesReaded = (Map<Class,ObservablesHandler>) xstream.fromXML(observablesReader);
+        for (Map.Entry<Class,ObservablesHandler> entry : observablesReaded.entrySet()) {
+            // add to the list of observers those readed from the file
+            ObservablesHandler clObservable = addObservable(entry.getKey());
+            for (ObserverListener observer : entry.getValue().getObservers()) {
+                // use addObserverListener method garanties safe init
+                clObservable.addObserverListener(observer);
+            }
+        }
+    }
+
+    public static void setObservers(Reader observablesReader) {
+        setObservers(observablesReader, new XStream(new DomDriver()));
+    }
+
+    /**
+     * @see javax.swing.ListModel#getSize()
+     */
+    public int getSize() {
+        int size = 0;
+        for (ObservablesHandler classObservable : observables.values()) {
+            size += classObservable.getObserversCount();
+        }
+        return size;
+    }
+
+    /**
+     * @see javax.swing.ListModel#getElementAt(int)
+     */
+    public Object getElementAt(int index) {
+        Set<Map.Entry<Class, ObservablesHandler>> entrySet = observables.entrySet();
+        Iterator<Map.Entry<Class, ObservablesHandler>> iterator = entrySet.iterator();
+        Map.Entry<Class, ObservablesHandler> current = iterator.next();
+        int count = current.getValue().getObserversCount();
+        while (count <= 0) {
+            current = iterator.next();
+            count = current.getValue().getObserversCount();
+        }
+        while (count <= index) {
+            current = iterator.next();
+            count += current.getValue().getObserversCount();
+        }
+        int realIndex = index - (count - current.getValue().getObserversCount());
+        assert realIndex < current.getValue().getObserversCount() : realIndex + " !< " + current.getValue().getObserversCount();
+        return new ClassAndObserver(current.getKey(), current.getValue().getObserver(realIndex));
+    }
+
+    /**
+     * @see javax.swing.ListModel#addListDataListener(javax.swing.event.ListDataListener)
+     */
+    public void addListDataListener(ListDataListener l) {
+        listDataListeners.add(l);
+    }
+
+    /**
+     * @see javax.swing.ListModel#removeListDataListener(javax.swing.event.ListDataListener)
+     */
+    public void removeListDataListener(ListDataListener l) {
+        listDataListeners.remove(l);
+    }
+
+    void fireObservableManagerStructureChanged() {
+        for (ListDataListener listDataListener : listDataListeners) {
+            listDataListener.contentsChanged(new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, 0, getSize()));
+        }
+    }
+
+    public static class ClassAndObserver {
+
+        private Class type;
+        private ObserverListener observer;
+
+        public ClassAndObserver(Class type, ObserverListener observer) {
+            this.type = type;
+            this.observer = observer;
+        }
+
+        public Class getType() {
+            return type;
+        }
+
+        public ObserverListener getObserver() {
+            return observer;
+        }
+
+        public String toString() {
+            return observer.getClass().getSimpleName() + " -> " + type.getSimpleName();
+        }
+
+        /**
+         * @see java.lang.Object#equals(java.lang.Object)
+         */
+        @Override
+        public boolean equals(Object obj) {
+            return obj.hashCode() == this.hashCode();
+        }
+
+        /**
+         * @see java.lang.Object#hashCode()
+         */
+        @Override
+        public int hashCode() {
+            return type.hashCode() + observer.hashCode();
+        }
+    }
+}
diff --git a/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java b/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..98a805408960c0b9a34c6feff4ef11e375827929
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/kernel/ObservablesHandler.java
@@ -0,0 +1,289 @@
+package fr.cemagref.observation.kernel;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+// TODO troduce in english
+public class ObservablesHandler {
+
+    private java.util.ArrayList<ObserverListener> observers;
+    private transient ObservableFetcher[] fetchers;
+
+    /**
+     * Constructeur.
+     * 
+     * @param cl La classe à laquelle on associe le présent ClassObservable
+     */
+    public ObservablesHandler(Class cl) {
+        // observable attributes initialisation
+        List<Field> v = new ArrayList<Field>();
+        List<Method> v2 = new ArrayList<Method>();
+
+        // observable methods initialisation
+        Class inheritanceNavigator = cl;
+        while (inheritanceNavigator != null) {
+            for (Field f : inheritanceNavigator.getDeclaredFields()) {
+                if (f.isAnnotationPresent(Observable.class)) {
+                    v.add(f);
+                }
+            }
+            for (Method m : inheritanceNavigator.getDeclaredMethods()) {
+                if (m.isAnnotationPresent(Observable.class)) {
+                    v2.add(m);
+                }
+            }
+            inheritanceNavigator = inheritanceNavigator.getSuperclass();
+        }
+
+        fetchers = new ObservableFetcher[v.size() + v2.size()];
+        for (int i = 0; i < v.size(); i++) {
+            fetchers[i] = new FieldFetcher(v.get(i));
+        }
+        for (int i = 0; i < v2.size(); i++) {
+            fetchers[v.size() + i] = new MethodFetcher(v2.get(i));
+        }
+
+        // observers intialisation
+        observers = new ArrayList<ObserverListener>();
+    }
+
+    public Object getValue(int i, Object instance) throws IllegalArgumentException, IllegalAccessException,
+            InvocationTargetException {
+        return fetchers[i].fetchValue(instance);
+    }
+
+    /** 
+     * Equivalent à getAttributes()[n], sauf s'il n'y a aucun attribut annoté comme observable (dans
+     * quel cas null est renvoyé).
+     * 
+     * @param n Un indice
+     * @return Le java.lang.reflect.Field correspondant au n-ième attribut, ou null si aucun attribut 
+     * n'est annoté comme observable.
+     */
+    public ObservableFetcher getObservableFetcher(int n) {
+        return fetchers[n];
+    }
+
+    public ObservableFetcher[] getObservableFetchers() {
+        return fetchers;
+    }
+
+    /** Renvoie l'attribut dont la description est passée en argument.
+     * 
+     * PERFS : Très mauvaises. A n'utiliser que pour un stockage initial de l'attribut
+     * afin de l'utiliser intensivement ensuite.
+     * 
+     * @param desc Une description
+     * @return L'attribut qui correspond à cette description.
+     */
+    public ObservableFetcher getObservableFetcher(String desc) {
+        if ((fetchers.length == 0) || (desc == null)) {
+            return null;
+        }
+        desc = desc.trim();
+        for (int i = 0; i < fetchers.length; i++) {
+            if (desc.equals(fetchers[i].getDescription().trim())) {
+                return fetchers[i];
+            }
+        }
+        return null;
+    }
+
+    public ObservableFetcher getObservableFetcherByName(String name) {
+        if ((fetchers.length == 0) || (name == null)) {
+            return null;
+        }
+        name = name.trim();
+        for (int i = 0; i < fetchers.length; i++) {
+            if (name.equals(fetchers[i].getDeclaredName().trim())) {
+                return fetchers[i];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return Le nombre d'attributes observables.
+     */
+    public int numberOfAttributes() {
+        return fetchers.length;
+    }
+
+    /**
+     * Accesseur vers les descriptions des attributes observables, dans le même ordre
+     * que getAttributes, c'est à dire que getAttributes()[n] ou getAttribute(n) ont la description
+     * getDescriptions()[n].
+     * 
+     * Si aucun attribut n'est annoté comme étant observable, renvoie null.
+     * 
+     *  PERFS : Comme les description ne sont pas destinées à être utilisées de façon intensive,
+     *  le tableau est reconstruit à chaque appel de la méthode.
+     * 
+     * @return Un tableau de descriptions des attributes annotés comme observables. 
+     * null si aucun attribut n'est annoté comme observable. 
+     */
+    public String[] getDescriptions() {
+        String[] t = new String[fetchers.length];
+        for (int i = 0; i < fetchers.length; i++) {
+            t[i] = fetchers[i].getDescription();
+        }
+        return t;
+    }
+
+    /** Equivalent à getAttribute(n).getAnnotation(Observable.class).description() sauf si
+     * aucun attribut n'est annoté comme étant observabel, dans quel cas on renvoie null.
+     * @param n
+     * @return La description du n-ième attribut.
+     */
+    public String getDescription(int n) {
+        return fetchers[n].getDescription();
+    }
+
+    public String getDeclaredName(int n) {
+        return fetchers[n].getDeclaredName();
+    }
+
+    /** Ajoute un ObserverListener à la liste.
+     * 
+     * @param ob L'ObserverListener à ajouter.
+     */
+    public ObserverListener addObserverListener(ObserverListener ob) {
+        observers.add(ob);
+        ob.addObservable(this);
+        return ob;
+    }
+
+    /** Retire un seul observerListener de la liste. Renvoie true s'il a effectivement été trouvé
+     * et retiré.
+     * @param ob L'ObserverListener à retirer. 
+     * @return
+     */
+    public boolean removeObserverListener(ObserverListener ob) {
+        boolean response = observers.remove(ob);
+        ObservableManager.getObservableManager().fireObservableManagerStructureChanged();
+        return response;
+    }
+
+    /**
+     * <code>size</code>
+     *
+     * @see java.util.ArrayList#size()
+     */
+    public int getObserversCount() {
+        return observers.size();
+    }
+
+    /**
+     * Notifie les changement aux observers déclarés. Pour le moment les appelle l'un après l'autre.
+     * 
+     * @param instanceEnCours
+     * @param t
+     */
+    public void fireChanges(Object instanceEnCours, long t) {
+        for (ObserverListener listener : observers) {
+            listener.valueChanged(this, instanceEnCours, t);
+        }
+    }
+
+    public Collection<ObserverListener> getObservers() {
+        return observers;
+    }
+
+    /**
+     * @see java.util.ArrayList#clear()
+     */
+    void clearObservers() {
+        this.observers.clear();
+    }
+
+    /**
+     * @see java.util.ArrayList#get(int)
+     */
+    public ObserverListener getObserver(int i) {
+        return observers.get(i);
+    }
+
+    public abstract class ObservableFetcher {
+
+        public ObservableFetcher(AccessibleObject accessibleObject) {
+            accessibleObject.setAccessible(true);
+        }
+
+        public abstract Object fetchValue(Object instance) throws IllegalArgumentException, IllegalAccessException,
+                InvocationTargetException;
+
+        public abstract String getDeclaredName();
+
+        public abstract String getDescription();
+
+        public abstract Class getDeclaredType();
+    }
+
+    public class MethodFetcher extends ObservableFetcher {
+
+        private Method method;
+
+        public MethodFetcher(Method method) {
+            super(method);
+            this.method = method;
+        }
+
+        @Override
+        public Object fetchValue(Object instance) throws IllegalArgumentException, IllegalAccessException,
+                InvocationTargetException {
+            // TODO add the ability to use arguments
+            return method.invoke(instance, new Object[]{});
+        }
+
+        @Override
+        public String getDescription() {
+            return method.getAnnotation(Observable.class).description();
+        }
+
+        @Override
+        public String getDeclaredName() {
+            return method.getName();
+        }
+
+        @Override
+        public Class getDeclaredType() {
+            return method.getReturnType();
+        }
+    }
+
+    public class FieldFetcher extends ObservableFetcher {
+
+        private Field field;
+
+        public FieldFetcher(Field field) {
+            super(field);
+            this.field = field;
+        }
+
+        @Override
+        public Object fetchValue(Object instance) throws IllegalArgumentException, IllegalAccessException,
+                InvocationTargetException {
+            return field.get(instance);
+        }
+
+        @Override
+        public String getDescription() {
+            return field.getAnnotation(Observable.class).description();
+        }
+
+        @Override
+        public String getDeclaredName() {
+            return field.getName();
+        }
+
+        @Override
+        public Class getDeclaredType() {
+            return field.getType();
+        }
+    }
+}
diff --git a/src/main/java/fr/cemagref/observation/kernel/ObserverListener.java b/src/main/java/fr/cemagref/observation/kernel/ObserverListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..597a9ff6129ad6b8de11493fc2da095d89bd8a3c
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/kernel/ObserverListener.java
@@ -0,0 +1,36 @@
+package fr.cemagref.observation.kernel;
+
+public interface ObserverListener {
+    /**
+     * <code>addObservable</code> is called when an observable is connected to
+     * this observable. It gives the possibility to make some init tasks.
+     * 
+     * @param classObservable
+     *            The new observable connected to this observer
+     */
+    public void addObservable(ObservablesHandler classObservable);
+
+    /**
+     * <code>valueChanged</code> is invoked when the observable has updated
+     * its value. It's time for the observer to do its job.
+     * 
+     * @param clObservable
+     *            the observable handler
+     * @param instance
+     *            the observable object
+     * @param t
+     *            the current time
+     */
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t);
+
+    /**
+     * <code>init</code> Called at begin of simulation
+     */
+    public void init();
+
+    /**
+     * <code>close</code> Called at end of simulation
+     * 
+     */
+    public void close();
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/CSVObserver.java b/src/main/java/fr/cemagref/observation/observers/CSVObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..3791290d8e03fe3362f7da1fdcde11e5cec8c70c
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/CSVObserver.java
@@ -0,0 +1,70 @@
+package fr.cemagref.observation.observers;
+
+import java.lang.reflect.InvocationTargetException;
+
+import fr.cemagref.observation.kernel.ObservablesHandler;
+import fr.cemagref.ohoui.annotations.Description;
+
+public class CSVObserver extends ConsoleObserver {
+
+    @Description(name="Field separator", tooltip="")
+    private char separator = ';';
+    
+    /** <code>classObservable</code> is used to display name of attributes as header */
+    private transient ObservablesHandler classObservable;
+
+    public CSVObserver(boolean sysout, String outputFile) {
+        super(sysout, outputFile);
+    }
+    
+    @Override
+    public void addObservable(ObservablesHandler classObservable) {
+        ObservablesHandler bak = this.classObservable;
+        this.classObservable = classObservable;
+        if (bak != null) // The observable has been changed 
+            this.init();
+    }
+
+    @Override
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+        StringBuffer buf = new StringBuffer();
+        StringBuffer sbSeparator = new StringBuffer(" "+this.separator+" ");
+        // print current Time
+        buf.append(t);
+        // print value of each field
+        for (int i =0;i<clObservable.numberOfAttributes();i++) {
+            buf.append(sbSeparator);
+            try {
+                buf.append(clObservable.getObservableFetcher(i).fetchValue(instance));
+            } catch (IllegalArgumentException e) {
+                buf.append("N/A");
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                buf.append("N/A");
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+    			e.printStackTrace();
+                return;
+            }
+        }
+        outputStream.println(buf);
+    }
+
+    @Override
+    public void init() {
+        super.init();
+        if (classObservable != null) {
+            // Headers printing
+            StringBuffer buf = new StringBuffer();
+            StringBuffer sbSeparator = new StringBuffer(" "+this.separator+" ");
+            buf.append("Time");
+            for (int i =0;i<classObservable.numberOfAttributes();i++) {
+                buf.append(sbSeparator);
+                buf.append(classObservable.getDescription(i));
+            }
+            outputStream.println(buf);
+        }
+    }
+    
+    
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java b/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..0a8af0a0bda8819bb912d9e35fc3377ce9c4665a
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/ConsoleObserver.java
@@ -0,0 +1,102 @@
+package fr.cemagref.observation.observers;
+
+import java.awt.Dimension;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+
+import fr.cemagref.observation.gui.Configurable;
+import fr.cemagref.observation.kernel.ObservablesHandler;
+import fr.cemagref.observation.kernel.ObserverListener;
+import fr.cemagref.ohoui.annotations.Anchor;
+import fr.cemagref.ohoui.annotations.Description;
+import fr.cemagref.ohoui.annotations.Link;
+import fr.cemagref.ohoui.filters.NoTransientField;
+import fr.cemagref.ohoui.swing.OhOUI;
+import fr.cemagref.ohoui.swing.OhOUIDialog;
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+
+public class ConsoleObserver implements ObserverListener, Configurable {
+
+    @Description(name="Use standard output",tooltip = "")
+    @Link(action="disable",target="filename")
+    private boolean sysout = true;
+    
+    @Anchor(id="filename")
+    private File outputFile = new File("");
+    
+    private transient File outputFileBak = outputFile;
+    protected transient PrintStream outputStream = System.out;
+
+    public ConsoleObserver(boolean sysout, String outputFile) {
+        this.sysout = sysout;
+        this.outputFile = new File(outputFile);
+        this.init();
+    }
+    
+    @Override
+    public void addObservable(ObservablesHandler classObservable) {
+        // nothing to do
+    }
+
+    @Override
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+        StringBuffer buf = new StringBuffer(t+" "+instance.getClass().getName() + " :\n");
+        for (int i =0;i<clObservable.numberOfAttributes();i++) {
+            buf.append("  "+clObservable.getDescription(i)+" = ");
+            try {
+                buf.append(clObservable.getObservableFetcher(i).fetchValue(instance));
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+    			e.printStackTrace();
+                return;
+            }
+            if (i<clObservable.numberOfAttributes()-1) buf.append("\n");
+        }
+        outputStream.println(buf);
+    }
+
+    protected void println(CharSequence message) {
+        if (sysout) {
+            outputStream.print(this.getClass().getSimpleName()+" :: ");
+        }
+        outputStream.println(message);
+    }
+        
+    @Override
+    public void configure() {
+        OhOUIDialog dialog = OhOUI.getDialog(null,this,new NoTransientField());
+        dialog.setSize(new Dimension(510, 160));
+        dialog.setVisible(true);
+        if (!outputFile.equals(outputFileBak)) init();
+        outputFileBak = outputFile;
+    }
+
+    @Override
+    public void init() {
+        if (sysout) {
+            outputStream = System.out;
+        } else {
+            try {
+                // it's rather better to use a buffetred outputstream, and to disable to default buffer of the PrintStream
+                outputStream = new PrintStream(new BufferedOutputStream(new FileOutputStream(outputFile), 1024), false);
+            } catch (FileNotFoundException e) {
+            	// TODO bring info to the user. Or prevent exception when directory of file doesn't exist
+                e.printStackTrace();
+                outputStream = System.out;
+            }
+        }    
+    }
+
+    @Override
+    public void close() {
+        if (outputStream != System.out)
+            outputStream.close();
+    }
+
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/MatrixCSVObserver.java b/src/main/java/fr/cemagref/observation/observers/MatrixCSVObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..032beaf065d46532ea6ee446b96c9f47357ca605
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/MatrixCSVObserver.java
@@ -0,0 +1,69 @@
+package fr.cemagref.observation.observers;
+
+import java.lang.reflect.InvocationTargetException;
+
+import fr.cemagref.observation.kernel.ObservablesHandler;
+import fr.cemagref.ohoui.annotations.Description;
+
+public class MatrixCSVObserver extends ConsoleObserver {
+
+    @Description(name = "Field separator", tooltip = "")
+    private char separator = ';';
+    /** <code>classObservable</code> is used to display name of attributes as header */
+    private transient ObservablesHandler classObservable;
+
+    public MatrixCSVObserver(boolean sysout, String outputFile) {
+        super(sysout, outputFile);
+    }
+
+    @Override
+    public void addObservable(ObservablesHandler classObservable) {
+        ObservablesHandler bak = this.classObservable;
+        this.classObservable = classObservable;
+        if (bak != null) // The observable has been changed 
+        {
+            this.init();
+        }
+    }
+
+    @Override
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+        StringBuilder buf = new StringBuilder();
+        StringBuilder sbSeparator = new StringBuilder(" ").append(this.separator).append(" ");
+        // print current Time
+        buf.append(t);
+        // print value of each field
+        for (int i = 0; i < clObservable.numberOfAttributes(); i++) {
+            buf.append(sbSeparator);
+            try {
+                buf.append(clObservable.getObservableFetcher(i).fetchValue(instance));
+            } catch (IllegalArgumentException e) {
+                buf.append("N/A");
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                buf.append("N/A");
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+                e.printStackTrace();
+                return;
+            }
+        }
+        outputStream.println(buf);
+    }
+
+    @Override
+    public void init() {
+        super.init();
+        if (classObservable != null) {
+            // Headers printing
+            StringBuilder buf = new StringBuilder();
+            StringBuilder sbSeparator = new StringBuilder(" " + this.separator + " ");
+            buf.append("Time");
+            for (int i = 0; i < classObservable.numberOfAttributes(); i++) {
+                buf.append(sbSeparator);
+                buf.append(classObservable.getDescription(i));
+            }
+            outputStream.println(buf);
+        }
+    }
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/XMLObserver.java b/src/main/java/fr/cemagref/observation/observers/XMLObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..503a6efdc8dbbbaeb0eea9fe4a27dcdbbaab4c53
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/XMLObserver.java
@@ -0,0 +1,159 @@
+package fr.cemagref.observation.observers;
+
+import fr.cemagref.observation.kernel.ObservablesHandler;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Observer that write data in XML format as defined by the Mexico working group.
+ */
+public class XMLObserver extends ConsoleObserver {
+
+  private static class ObservableDataInfos {
+
+    String tagOpeningWithName;
+    String tagOpening;
+    String tagClosing;
+    int numberOfDimensions;
+  }
+  private static transient Map<Class, String> typeForXml;
+  private transient List<ObservableDataInfos> observableDataInfosList;
+
+  public XMLObserver(boolean sysout, String outputFile) {
+    super(sysout, outputFile);
+  }
+
+  @Override
+  public void init() {
+    super.init();
+    if (typeForXml == null) {
+      typeForXml = new HashMap<Class, String>();
+      typeForXml.put(Double.class, "d");
+      typeForXml.put(double.class, "d");
+      typeForXml.put(Integer.class, "i");
+      typeForXml.put(int.class, "i");
+      typeForXml.put(String.class, "s");
+    }
+    if (observableDataInfosList == null) {
+      observableDataInfosList = new ArrayList<ObservableDataInfos>();
+    }
+    outputStream.print("<outputData>\n");
+  }
+
+  @Override
+  public void addObservable(ObservablesHandler classObservable) {
+    if (typeForXml == null) {
+      init();
+    }
+    if (observableDataInfosList == null) {
+      init();
+    }
+    // Storing the infos for this observable
+    ObservableDataInfos infos;
+    for (int i = 0; i < classObservable.numberOfAttributes(); i++) {
+      infos = new ObservableDataInfos();
+      ObservablesHandler.ObservableFetcher fetcher = classObservable.getObservableFetcher(i);
+      Class observableType = fetcher.getDeclaredType();
+      // if the type is an array, going in depth to find the final component type and the number of dimensions
+      infos.numberOfDimensions = 0;
+      while (observableType.isArray()) {
+        infos.numberOfDimensions++;
+        observableType = observableType.getComponentType();
+      }
+      infos.tagOpening = "<" + typeForXml.get(observableType) + ">";
+      infos.tagOpeningWithName = "<" + typeForXml.get(observableType) + " name =\"";
+      infos.tagClosing = "</" + typeForXml.get(observableType) + ">";
+      observableDataInfosList.add(infos);
+    }
+  }
+
+  @Override
+  public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+    for (int i = 0; i < clObservable.numberOfAttributes(); i++) {
+      try {
+        //System.out.println("XMLObserver::valueChanged" + clObservable.getObservableFetcher(i).fetchValue(instance) + clObservable.getDeclaredName(i) + clObservable.getDescription(i));
+        outputStream.print("<step time =\"");
+        outputStream.print(t);
+        outputStream.println("\">");
+        printData(observableDataInfosList.get(i), clObservable.getObservableFetcher(i).fetchValue(instance), clObservable.getDeclaredName(i),
+                clObservable.getDescription(i));
+        outputStream.println("</step>");
+      } catch (IllegalArgumentException e) {
+        e.printStackTrace();
+      } catch (IllegalAccessException e) {
+        e.printStackTrace();
+      } catch (InvocationTargetException e) {
+        e.printStackTrace();
+        return;
+      }
+    }
+  }
+
+  private void printData(ObservableDataInfos infos, Object data, String declaredName, String description) {
+    if (infos.numberOfDimensions > 0) {
+      // Open the matrix tag
+      outputStream.print("<m name=\"");
+      outputStream.print(description);
+      outputStream.print("\">\n");
+      // print metadata for each dimensions
+      Object dimension = data;
+      int dimensionExtent;
+      for (int i = 1; i <= infos.numberOfDimensions; i++) {
+        outputStream.print("<dimension name=\"dim");
+        outputStream.print(i);
+        outputStream.print("\" size=\"");
+        dimensionExtent = Array.getLength(dimension);
+        outputStream.print(dimensionExtent);
+        outputStream.println("\"><label></label></dimension>");
+        if (dimensionExtent > 0) {
+          dimension = Array.get(dimension, 0);
+        } else {
+          outputStream.println("</m>");
+          return;
+        }
+      }
+      // print the matrix data
+      for (int i = 0; i < Array.getLength(data); i++) {
+        printMatrixData(infos, Array.get(data, i), declaredName, description, 0);
+      }
+      // close the matrix tag
+      outputStream.println("</m>");
+    } else {
+      printScalarData(infos, data, description);
+    }
+  }
+
+  private void printMatrixData(ObservableDataInfos infos, Object data, String declaredName, String description, int depth) {
+    if (data.getClass().isArray()) {
+      for (int i = 0; i < Array.getLength(data); i++) {
+        printMatrixData(infos, Array.get(data, i), declaredName, description, depth + 1);
+      }
+    } else {
+      printScalarData(infos, data);
+    }
+  }
+
+  private void printScalarData(ObservableDataInfos infos, Object data, String description) {
+    outputStream.print(infos.tagOpeningWithName);
+    outputStream.print(description);
+    outputStream.print("\">");
+    outputStream.print(data);
+    outputStream.println(infos.tagClosing);
+  }
+
+  private void printScalarData(ObservableDataInfos infos, Object data) {
+    outputStream.print(infos.tagOpening);
+    outputStream.print(data);
+    outputStream.println(infos.tagClosing);
+  }
+
+  @Override
+  public void close() {
+    outputStream.print("</outputData>");
+    super.close();
+  }
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/XMLObserverSelectable.java b/src/main/java/fr/cemagref/observation/observers/XMLObserverSelectable.java
new file mode 100644
index 0000000000000000000000000000000000000000..7982bef9402d706b4b333d43b0d3f6d60fd1c887
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/XMLObserverSelectable.java
@@ -0,0 +1,138 @@
+package fr.cemagref.observation.observers;
+
+import fr.cemagref.observation.kernel.ObservablesHandler;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Observer that write data in XML format as defined by the Mexico working group.
+ */
+public class XMLObserverSelectable extends ConsoleObserver {
+
+    protected String observableVariable;
+    protected transient ObservablesHandler.ObservableFetcher variable;
+    protected transient String tagOpeningWithName;
+    protected transient String tagOpening;
+    protected transient String tagClosing;
+    protected transient int numberOfDimensions;
+    private static transient Map<Class, String> typeForXml;
+
+    public XMLObserverSelectable(boolean sysout, String outputFile) {
+        super(sysout, outputFile);
+    }
+
+    @Override
+    public void init() {
+        super.init();
+        if (typeForXml == null) {
+            typeForXml = new HashMap<Class, String>();
+            typeForXml.put(Double.class, "d");
+            typeForXml.put(double.class, "d");
+            typeForXml.put(Integer.class, "i");
+            typeForXml.put(int.class, "i");
+            typeForXml.put(String.class, "s");
+        }
+    }
+
+    @Override
+    public void addObservable(ObservablesHandler classObservable) {
+        if (typeForXml == null) {
+            init();
+        }
+        // Storing the infos for this observable
+        variable = classObservable.getObservableFetcherByName(observableVariable);
+        if (variable != null) {
+            Class observableType = variable.getDeclaredType();
+            // if the type is an array, going in depth to find the final component type and the number of dimensions
+            numberOfDimensions = 0;
+            while (observableType.isArray()) {
+                numberOfDimensions++;
+                observableType = observableType.getComponentType();
+            }
+            tagOpening = "<" + typeForXml.get(observableType) + ">";
+            tagOpeningWithName = "<" + typeForXml.get(observableType) + " name =\"";
+            tagClosing = "</" + typeForXml.get(observableType) + ">";
+        }
+    }
+
+    @Override
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+        if (variable != null) {
+            try {
+                outputStream.print("<step time =\"");
+                outputStream.print(t);
+                outputStream.println("\">");
+                printData(variable.fetchValue(instance), variable.getDeclaredName(),
+                        variable.getDescription());
+                outputStream.println("</step>");
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            } catch (InvocationTargetException e) {
+                e.printStackTrace();
+                return;
+            }
+        }
+    }
+
+    private void printData(Object data, String declaredName, String description) {
+        if (numberOfDimensions > 0) {
+            // Open the matrix tag
+            outputStream.print("<m name=\"");
+            outputStream.print(description);
+            outputStream.print("\">\n");
+            // print metadata for each dimensions
+            Object dimension = data;
+            int dimensionExtent;
+            for (int i = 1; i <= numberOfDimensions; i++) {
+                outputStream.print("<dimension name=\"dim");
+                outputStream.print(i);
+                outputStream.print("\" size=\"");
+                dimensionExtent = Array.getLength(dimension);
+                outputStream.print(dimensionExtent);
+                outputStream.println("\"><label></label></dimension>");
+                if (dimensionExtent > 0) {
+                    dimension = Array.get(dimension, 0);
+                } else {
+                    outputStream.println("</m>");
+                    return;
+                }
+            }
+            // print the matrix data
+            for (int i = 0; i < Array.getLength(data); i++) {
+                printMatrixData(Array.get(data, i), declaredName, description, 0);
+            }
+            // close the matrix tag
+            outputStream.println("</m>");
+        } else {
+            printScalarData(data, description);
+        }
+    }
+
+    private void printMatrixData(Object data, String declaredName, String description, int depth) {
+        if (data.getClass().isArray()) {
+            for (int i = 0; i < Array.getLength(data); i++) {
+                printMatrixData(Array.get(data, i), declaredName, description, depth + 1);
+            }
+        } else {
+            printScalarData(data);
+        }
+    }
+
+    private void printScalarData(Object data, String description) {
+        outputStream.print(tagOpeningWithName);
+        outputStream.print(description);
+        outputStream.print("\">");
+        outputStream.print(data);
+        outputStream.println(tagClosing);
+    }
+
+    private void printScalarData(Object data) {
+        outputStream.print(tagOpening);
+        outputStream.print(data);
+        outputStream.println(tagClosing);
+    }
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/GraphType.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/GraphType.java
new file mode 100644
index 0000000000000000000000000000000000000000..3fd8307b530d0de142e800ce3e125466ec57bf3f
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/GraphType.java
@@ -0,0 +1,30 @@
+package fr.cemagref.observation.observers.jfreechart;
+
+public enum GraphType {
+	
+	POINT(1,"Points"),
+	LINE(2,"Lignes"),
+	AREA(3,"Aires"),
+	AREASTEP(4,"Aires en escalier"),
+	STEP(5,"Escalier");
+	
+	private int code;
+	private String description;
+	
+	private GraphType(int i,String description) {
+		code=i;
+		this.description=description;
+	}
+	
+	public int code() {
+		return code;
+	}
+	
+	public String getDescription() {
+		return description;
+	}
+	
+	public String toString() {
+		return getDescription();
+	}
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java
new file mode 100644
index 0000000000000000000000000000000000000000..d3f463e9d34937e164619a906b9201e0556117bc
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalChart.java
@@ -0,0 +1,128 @@
+package fr.cemagref.observation.observers.jfreechart;
+
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.xy.XYSeriesCollection;
+
+import fr.cemagref.observation.gui.Configurable;
+import fr.cemagref.observation.gui.Drawable;
+import fr.cemagref.observation.kernel.ObservablesHandler;
+import fr.cemagref.observation.kernel.ObserverListener;
+import fr.cemagref.ohoui.filters.NoTransientField;
+import fr.cemagref.ohoui.swing.OUIPanel;
+import fr.cemagref.ohoui.swing.OhOUI;
+import fr.cemagref.ohoui.swing.OhOUIDialog;
+
+public abstract class TemporalChart implements ObserverListener, Configurable, Drawable {
+	
+    private transient ChartPanel chartPanel;
+    private transient JFreeChart jfchart;
+	protected transient XYSeriesCollection dataset;
+    protected GraphType graphType = GraphType.LINE;
+    
+    /**
+     * <code>variable</code> is the variable to represent
+     */
+    protected transient ObservablesHandler.ObservableFetcher variable;
+    protected transient ObservablesHandler classObservable;
+	private String title = "", xAxisLabel = "Time", yAxisLabel = "";
+	
+    public TemporalChart() {
+        graphTypeUpdated();
+    }
+    
+    public TemporalChart(ObservablesHandler.ObservableFetcher variable) {
+        this();
+        this.variable = variable;
+        variableUpdated();
+    }
+    
+    protected void variableUpdated() {
+        if (variable != null) {
+            yAxisLabel = variable.getDescription();
+            title = "Observation of " + yAxisLabel;
+        }
+    }
+    
+    protected void graphTypeUpdated() {
+		PlotOrientation orientation = PlotOrientation.VERTICAL;
+		boolean legend = true;
+		boolean tooltips = true;
+		boolean urls = false;
+		
+		if(graphType.equals(GraphType.POINT)){
+			jfchart=ChartFactory.createScatterPlot(title,xAxisLabel,yAxisLabel,dataset,orientation,legend,tooltips,urls);
+		}else if(graphType.equals(GraphType.LINE)){
+			jfchart = ChartFactory.createXYLineChart(title,xAxisLabel,yAxisLabel,dataset,orientation,legend,tooltips,urls);
+		}else if(graphType.equals(GraphType.AREA)){
+			jfchart = ChartFactory.createXYAreaChart(title,xAxisLabel,yAxisLabel,dataset,orientation,legend,tooltips,urls);
+		}else if(graphType.equals(GraphType.STEP)){
+			jfchart = ChartFactory.createXYStepChart(title,xAxisLabel,yAxisLabel,dataset,orientation,legend,tooltips,urls);
+		}else if(graphType.equals(GraphType.AREASTEP)){
+			jfchart = ChartFactory.createXYStepAreaChart(title,xAxisLabel,yAxisLabel,dataset,orientation,legend,tooltips,urls);
+		}
+        if (chartPanel == null)
+            chartPanel = new ChartPanel(jfchart);
+        else
+            chartPanel.setChart(jfchart);
+	}
+	
+	public JFreeChart getJfchart() {
+		return jfchart;
+	}
+
+    public void configure() {
+        ObservablesHandler.ObservableFetcher variableBak = variable;
+        OhOUIDialog dialog = OhOUI.getDialog(null,this,new NoTransientField());
+        JComboBox comboBox = new JComboBox(classObservable.getDescriptions());
+        if (variable != null)
+            comboBox.setSelectedItem(variable.getDescription());
+        OUIPanel ouiPanel = OUIPanel.makeLabelComponentOUIPanel(variable, comboBox, "Variable", "");
+        dialog.getContentPane().add(ouiPanel.getPanel(),0);
+        dialog.pack();
+        dialog.setVisible(true);
+        variable = classObservable.getObservableFetcher((String)comboBox.getSelectedItem());
+        if (variable != null)
+            if ( ! variable.equals(variableBak))
+                variableUpdated();
+        graphTypeUpdated();
+    } 
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#addObservable(fr.cemagref.observation.kernel.ObservablesHandler)
+     */
+    public void addObservable(ObservablesHandler classObservable) {
+        this.classObservable = classObservable;
+    }
+
+    /**
+     * @see fr.cemagref.observation.gui.Drawable#getDisplay()
+     */
+    public JComponent getDisplay() {
+        return chartPanel;
+    }
+
+    /**
+     * @see fr.cemagref.observation.gui.Drawable#getTitle()
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#init()
+     */
+    public void init() {
+        if (classObservable != null)
+            if (classObservable.numberOfAttributes() > 0)
+                variable = classObservable.getObservableFetcher(0);
+            // TODO classObservable.getAttributes().length *must* be > 0
+    }
+   
+    
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalMeanChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalMeanChart.java
new file mode 100644
index 0000000000000000000000000000000000000000..c91ee25bd5dfc93b5f2e80e82de545c0970c5335
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalMeanChart.java
@@ -0,0 +1,109 @@
+package fr.cemagref.observation.observers.jfreechart;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+import fr.cemagref.observation.kernel.ObservablesHandler;
+
+/**
+ * <code>TemporalMeanChart</code> allow to draw a chart representing the mean
+ * of several temporal series
+ */
+public class TemporalMeanChart extends TemporalChart {
+
+    /**
+     * <code>serie</code> store the temporal values of the mean, ready to draw
+     */
+    private transient XYSeries serie;
+
+    /**
+     * <code>temporalValues</code>
+     */
+    private transient Map<Long, List<Double>> temporalValues = new HashMap<Long, List<Double>>();
+
+    /**
+     * This constructor init the chart with a line drawstyle.
+     * 
+     * @param variable
+     *            the variable to represent
+     */
+    public TemporalMeanChart(ObservablesHandler.ObservableFetcher variable) {
+        super(variable);
+        init();
+    }
+    
+    /**
+     * <code>mean</code> computes the mean of the value of the list passed as
+     * arguments
+     */
+    private double mean(List<Double> list) {
+        double mean = 0;
+        for (Double d : list) {
+            mean += d;
+        }
+        mean = mean / list.size();
+        return mean;
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#valueChanged(fr.cemagref.observation.kernel.ObservablesHandler,
+     *      java.lang.Object, int)
+     */
+    @Override
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+        // we fetch the value of the observable
+        double value;
+        try {
+            value = (Double)variable.fetchValue(instance);
+        } catch (IllegalArgumentException e1) {
+            e1.printStackTrace();
+            return;
+        } catch (IllegalAccessException e1) {
+            e1.printStackTrace();
+            return;
+        } catch (InvocationTargetException e) {
+			e.printStackTrace();
+            return;
+		}
+
+        int index = serie.indexOf(t);
+        if (index < 0) {
+            // This is the first value for this time step
+            List<Double> list = new ArrayList<Double>();
+            list.add(value);
+            temporalValues.put(t, list);
+            // For instance, the mean is this first value
+            serie.add(t, value);
+        } else {
+            // we add this new value to the list
+            List<Double> list = temporalValues.get(t);
+            list.add(value);
+            // and we update the mean
+            serie.getDataItem(index).setY(mean(list));
+        }
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#init()
+     */
+    @Override
+    public void init() {
+        super.init();
+        serie = new XYSeries("values");
+        dataset = new XYSeriesCollection(serie);
+        graphTypeUpdated();
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#close()
+     */
+    public void close() {
+    }
+
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalSerieChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalSerieChart.java
new file mode 100644
index 0000000000000000000000000000000000000000..f86001a3a9e61c26c58ded618eeef64b4eccf3c0
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/TemporalSerieChart.java
@@ -0,0 +1,75 @@
+package fr.cemagref.observation.observers.jfreechart;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+import fr.cemagref.observation.kernel.ObservablesHandler;
+
+public class TemporalSerieChart extends TemporalChart {
+
+    public TemporalSerieChart() {
+        super();
+        init();
+    }
+    
+    public TemporalSerieChart(ObservablesHandler.ObservableFetcher variable) {
+        super(variable);
+        init();
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#valueChanged(fr.cemagref.observation.kernel.ObservablesHandler, java.lang.Object, int)
+     */
+    @Override
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+    	// we fetch the value of the observable
+        double value;
+        try {
+        	Object objectValue = variable.fetchValue(instance);
+        	if (objectValue instanceof Integer)
+        		value = (Integer)objectValue;
+        	else
+        		value = (Double)objectValue;
+        } catch (IllegalArgumentException e1) {
+            e1.printStackTrace();
+            return;
+        } catch (IllegalAccessException e1) {
+            e1.printStackTrace();
+            return;
+        } catch (InvocationTargetException e) {
+			e.printStackTrace();
+            return;
+        }
+
+        int index = dataset.indexOf(instance.hashCode());
+        XYSeries serie;
+        if (index >= 0) {
+            serie = dataset.getSeries(index);
+        } else {
+            // This is the first value of the observable 
+            serie = new XYSeries(instance.hashCode());
+            dataset.addSeries(serie);
+        }
+        serie.add(t, value);
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#init()
+     */
+    @Override
+    public void init() {
+        super.init();
+        dataset = new XYSeriesCollection();
+        graphTypeUpdated();
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#close()
+     */
+    @Override
+    public void close() {
+    }
+
+}
diff --git a/src/main/java/fr/cemagref/observation/observers/jfreechart/XYSeriesChart.java b/src/main/java/fr/cemagref/observation/observers/jfreechart/XYSeriesChart.java
new file mode 100644
index 0000000000000000000000000000000000000000..e96691e5c73cc17f6cdbc42c6fab2f96fbc1b229
--- /dev/null
+++ b/src/main/java/fr/cemagref/observation/observers/jfreechart/XYSeriesChart.java
@@ -0,0 +1,210 @@
+package fr.cemagref.observation.observers.jfreechart;
+
+import com.thoughtworks.xstream.XStream;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+
+import org.jfree.chart.ChartFactory;
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.xy.XYSeriesCollection;
+
+import fr.cemagref.observation.gui.Configurable;
+import fr.cemagref.observation.gui.Drawable;
+import fr.cemagref.observation.kernel.ObservablesHandler;
+import fr.cemagref.observation.kernel.ObservablesHandler.ObservableFetcher;
+import fr.cemagref.observation.kernel.ObserverListener;
+import fr.cemagref.ohoui.filters.NoTransientField;
+import fr.cemagref.ohoui.swing.OUIPanel;
+import fr.cemagref.ohoui.swing.OhOUI;
+import fr.cemagref.ohoui.swing.OhOUIDialog;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+import org.jfree.data.xy.XYDataset;
+
+public class XYSeriesChart implements ObserverListener, Configurable, Drawable {
+
+    private transient ChartPanel chartPanel;
+    private transient JFreeChart jfchart;
+    protected transient XYDataset dataset;
+    /**
+     * <code>variable</code> is the variable to represent
+     */
+    protected transient List<ObservableFetcher> variableXY;
+    protected transient ObservablesHandler classObservable;
+    protected transient List<Integer> xIndex = null;
+    protected transient List<Integer> yIndex = null;
+    protected GraphType graphType = GraphType.LINE;
+    private String title = "",  xAxisLabel = "x",  yAxisLabel = "y";
+
+    public XYSeriesChart() {
+        graphTypeUpdated();
+    }
+
+    public XYSeriesChart(List<ObservableFetcher> xy) {
+        this();
+        this.variableXY = xy;
+        variableUpdated();
+    }
+
+    protected void variableUpdated() {
+        if ((xIndex != null) && (xIndex.size() > 0)) {
+            xAxisLabel = variableXY.get(xIndex.get(0)).getDescription();
+        }
+        if ((yIndex != null) && (yIndex.size() > 0)) {
+            yAxisLabel = variableXY.get(yIndex.get(1)).getDescription();
+        }
+        title = "Observation of " + yAxisLabel;
+    }
+
+    protected void graphTypeUpdated() {
+        PlotOrientation orientation = PlotOrientation.VERTICAL;
+        boolean legend = true;
+        boolean tooltips = true;
+        boolean urls = false;
+
+        if (graphType.equals(GraphType.POINT)) {
+            jfchart = ChartFactory.createScatterPlot(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        } else if (graphType.equals(GraphType.LINE)) {
+            jfchart = ChartFactory.createXYLineChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        } else if (graphType.equals(GraphType.AREA)) {
+            jfchart = ChartFactory.createXYAreaChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        } else if (graphType.equals(GraphType.STEP)) {
+            jfchart = ChartFactory.createXYStepChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        } else if (graphType.equals(GraphType.AREASTEP)) {
+            jfchart = ChartFactory.createXYStepAreaChart(title, xAxisLabel, yAxisLabel, dataset, orientation, legend, tooltips, urls);
+        }
+        if (chartPanel == null) {
+            chartPanel = new ChartPanel(jfchart);
+        } else {
+            chartPanel.setChart(jfchart);
+        }
+    }
+
+    public JFreeChart getJfchart() {
+        return jfchart;
+    }
+
+    @Override
+    public void configure() {
+        List<ObservableFetcher> variableBak = variableXY;
+        OhOUIDialog dialog = OhOUI.getDialog(null, this, new NoTransientField());
+// panel for X variable
+        JComboBox comboBoxX = new JComboBox(classObservable.getDescriptions());
+        if (variableXY != null) {
+            comboBoxX.setSelectedItem(variableXY.get(0).getDescription());
+        }
+        OUIPanel ouiPanelX = OUIPanel.makeLabelComponentOUIPanel(variableXY, comboBoxX, "Variable for X axis", "");
+        dialog.getContentPane().add(ouiPanelX.getPanel(), 0);
+
+// panel for Y variable
+        JComboBox comboBoxY = new JComboBox(classObservable.getDescriptions());
+        if (variableXY != null) {
+            comboBoxY.setSelectedItem(variableXY.get(1).getDescription());
+        }
+        OUIPanel ouiPanelY = OUIPanel.makeLabelComponentOUIPanel(variableXY, comboBoxY, "Variable for Y axis", "");
+        dialog.getContentPane().add(ouiPanelY.getPanel(), 1);
+
+        dialog.pack();
+        dialog.setVisible(true);
+        variableXY = new ArrayList<ObservableFetcher>();
+        variableXY.add(classObservable.getObservableFetcher((String) comboBoxX.getSelectedItem()));
+        variableXY.add(classObservable.getObservableFetcher((String) comboBoxY.getSelectedItem()));
+        if (variableXY != null) {
+            if (!variableXY.equals(variableBak)) {
+                variableUpdated();
+            }
+        }
+        graphTypeUpdated();
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#addObservable(fr.cemagref.observation.kernel.ObservablesHandler)
+     */
+    @Override
+    public void addObservable(ObservablesHandler classObservable) {
+        this.classObservable = classObservable;
+    }
+
+    /**
+     * @see fr.cemagref.observation.gui.Drawable#getDisplay()
+     */
+    @Override
+    public JComponent getDisplay() {
+        return chartPanel;
+    }
+
+    /**
+     * @see fr.cemagref.observation.gui.Drawable#getTitle()
+     */
+    @Override
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * @see fr.cemagref.observation.kernel.ObserverListener#init()
+     */
+    @Override
+    public void init() {
+        if (classObservable != null) {
+            if (classObservable.numberOfAttributes() > 0) {
+                variableXY = new ArrayList<ObservableFetcher>();
+
+                variableXY.add(classObservable.getObservableFetcher(0));
+                variableXY.add(classObservable.getObservableFetcher(1));
+            }
+        }
+        // TODO classObservable.getAttributes().length *must* be > 0
+        dataset = new XYSeriesCollection();
+        graphTypeUpdated();
+    }
+
+    @Override
+    public void valueChanged(ObservablesHandler clObservable, Object instance, long t) {
+        // we fetch the value of the observable
+        List<Object> value = new ArrayList<Object>();
+        try {
+            for (ObservableFetcher va : variableXY) {
+                Object objectValue = va.fetchValue(instance);
+                if (objectValue instanceof Integer) {
+                    value.add((Integer) objectValue);
+                } else {
+                    value.add((Double) objectValue);
+                }
+            }
+        } catch (IllegalArgumentException e1) {
+            e1.printStackTrace();
+            return;
+        } catch (IllegalAccessException e1) {
+            e1.printStackTrace();
+            return;
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+            return;
+        }
+
+    /* TODO a revoir
+    int index = dataset.indexOf(instance.hashCode());
+    XYSeries serie;
+    if (index >= 0) {
+    serie = dataset.getSeries(index);
+    } else {
+    // This is the first value of the observable 
+    serie = new XYSeries(instance.hashCode());
+    dataset.addSeries(serie);
+    }
+    serie.add(t, value);
+     * */
+    }
+
+    @Override
+    public void close() {
+    }
+
+    public static void main(String[] args) {
+        System.out.println(new XStream().toXML(new XYSeriesChart()));
+    }
+}