samedi 14 juin 2008

Delphi Runtime Inspector

Il arrive, parfois, en cours de debug avec Delphi, de faire des évaluations avec CTRL+F7, du genre MonDataset.FieldByName('TOTO').AsString pour savoir sur quelles données on travaille. C'est facile, mais "un peu laborieux", surtout si le dataset en question contient beaucoup de données.

A regarder le problème de plus prêt, on remarque qu'il se pose à chaque fois que l'on a un objet "complexe", c'est à dire que sa classe est issue d'un lignée de dérivation plus ou moins longue.
En fait l'inspecteur d'objet de Delphi, n'est pas vraiment un inspecteur de TObject (il ne donne pas l'héritage ou la taille de la classe de l'instance). Il s'agit d'un inspecteur de TPersistent, c'est tout. Pas d'info concernant les données de TComponent, de TWinControl ou de n'importe quelle classe descendant de TPersistent.

Runtime Delphi Inspector est une librairie capable de me fournir un inspecteur d'objet à l'exécution. Cet inspecteur d'objet est personnalisable en fonction de la classe de l'objet à inspecter. Par exemple, l'inspecteur de TDataset contient un DBGrid capable d'afficher les données du TDataset à afficher. Une fenêtre d'inspecteur se compose de plusieurs onglets, associés à chaque niveau d'héritage.

Pour télécharger cette librairie : RtInspector

mercredi 21 mai 2008

Le 68000 et les périphériques 6800.

Le 68000 représentait un changement majeur dans la gamme de processeur motorola. En effet un processeur 16 bits à 8 mhz, c'était largement plus rapide que le 6800, un processeur 8 bits, principal processeur de la marque. En effet il existait uniquement des versions à 1, 1.5 et 2 mhz. Il était doté d'une gamme de contrôleurs de périphériques variés comme le PIA 6821 (2 ports parallèles 8 bits) ou le ACIA 6850 (un port série). Les fréquences d'horloges maximums pour ces contrôleurs étaient alignés sur celles du 6800.

Les concepteurs du 68000 ont doté de la possibilité de se "ralentir" en générant un signal d'horloge qui dure 10 cycles d'horloge. L'objectif était de pouvoir utiliser les contrôleurs du 6800, soit pour une raison de coût, soit pour bénéficier dès la sortie du processeur de toute une gamme de contrôleurs.

De nombreux micro-ordinateurs grand public ont bénéficiés de cette caractéristique, comme le mac d'apple qui contenait un VIA 6522 ou l'atari ST qui avaient deux ACIA 6850.

De delphi à linux, programmation des timers

Le composant TTimer sous delphi est un composant capable de faire un appel régulier et répétitif à une procédure utilisateur.
Le délai entre les appels est réglable. Le principe de fonctionnement est simple : il s'agit de créer une fenêtre non visible, associée à une procédure de fenêtre (wndproc) capable de gérer le message WM_TIMER. En initialise les appels ensuite avec une api praticulière de windows. Le noyau Windows va,à partir de là, envoyer régulièrement un message WM_TIMER à cette fenêtre.

Ceci étant vu, je vais vous proposer maintenant de reproduire ce type de comportement sur linux.

Ce système peut quand à lui répondre à des signaux extérieur à l'application. Ces signaux peuvent être détournés par le programme vers une fonction de gestion. Si le programme ne le fait pas, le noyau tue l'application. C'est ainsi que fonctionne CTRL+C qui envoie à l'application courante un SIGINT, le signal d'arrêt du programme. Si le programme n'a pas de gestion particulière de ce signal, le noyau va effectivement stopper le programme. Si le programme gère ce signal, le programmeur devra prévoir une stratégie de sortie.

Revenons au timer. Il existe un signal SIGALRM qui est envoyé régulièrement par le noyau à une application. Ce signal sera envoyé sur demande de l'application. Bien entendu, comme tout signal, s'il n'est pas géré par l'application, il provoquera l'arrêt du programme. Si on le détourne vers une fonction, cette fonction sera appelée régulièrement.

Voici un exemple de source C sur l'utilisation des alarmes sous linux:


/*
=============================================================================
Name : timer.c
Author : OT
Description : Comment coder l'équivalent du TTimer de delphi en c sous linux ?
=============================================================================
*/

#include ‹stdio.h>
#include ‹stdlib.h>
#include ‹signal.h>
#include ‹sys/types.h>
#include ‹unistd.h>
#include ‹errno.h>
#include ‹sys/wait.h>

void evenementTimer() {
printf("Top timer\n");
alarm(1);
}

int main(void) {
signal(SIGALRM, evenementTimer);
alarm(1);
// c'est mal de faire une attente active....
for (;;) {
}
}

Le bus I2C et la télévision

Dans un précédent article j'avais fait une brève présentation du bus I2C. Je vais vous présenter
maintenant quelques composants I2C utilisés en télévision. Il s'agit juste d'une liste très courte, le nombre de composants I2C est en effet très important.
Cela veut dire que toutes ces fonctions sont contrôlables par un microprocesseur ou par un pc.


STV942x : contrôleur OSD (incrustation vidéo)

TDA933x : processeur vidéo (contrôle de luminance et chrominance, balayage vertical 50,60,100 et 120 hertz, balayage horizontal)

SAA5243/45 : décodeur télétexte

SAA9055P : décodeur numérique SECAM

SAA9062/63/64 : contrôleur de déviation

SAB3035/36/37 : syntonisateur

SAA9068 : contrôle du PIP (picture in picture)

TDA8405
: contrôleur son stéréo

TDA8440 : commutateur audio / video

TDA8461 : Décodeur PAL/NTSC

jeudi 8 mai 2008

Google, webservices et cartographie

Google webservices et cartographie

L'api la plus connue de google maps est la librairie javascript qui permet de faire du mashup avec leurs cartes. Il existe toutefois d'autres possibilitées pour exploiter leurs données. On peut facilement géolocaliser une adresse postale et la convertir en coordonnées géographiques.

Une simple requete http GET suffit :

http://maps.google.com/maps/geo?q=2+rue+victor+hugo+26000+valence+fr&output=csv&key=placer ici votre clé google maps api

Le format de retour est un fichier csv d'une ligne et de 4 colonnes
La colonne 1 correspond à un code retour d'erreur ou de succès













Code statut de la requèteDescription
(200) G_GEO_SUCCESSAucune erreur ne s'est produite. L'adresse a été analysée avec succès et ses coordonnées GPS (Latitude, Longitude) ont été retournées.
(400) G_GEO_BAD_REQUESTLa demande n'a pu être analysée avec succès.
(500) G_GEO_SERVER_ERRORLa demande n'a pu être traitée avec succès. La raison exacte de l'échec est inconnue.
(601) G_GEO_MISSING_QUERYLe paramètre "q" de la requète HTTP est manquant ou n'a aucune valeur. Pour les demandes de "géocodage", cela signifie qu'une adresse vide a été indiquée dans la requète. Pour les demandes de directions, cela signifie qu'aucune question n'a été indiquée dans la requète.
(601) G_GEO_MISSING_ADDRESSSynonyme de G_GEO_MISSING_QUERY.
(602) G_GEO_UNKNOWN_ADDRESSAucun lieu géographique correspondant à l'adresse indiquée n'a pu être trouvé. Cela peut être dû au fait que l'adresse est relativement nouvelle, ou qu'elle est peut être incorrecte.
(603) G_GEO_UNAVAILABLE_ADDRESSLes coordonnées GPS (Latitude, Longitude) pour l'adresse donnée ou l'itinéraire demandé n'ont pu être retournées pour des raisons légales ou contractuelles.
(604) G_GEO_UNKNOWN_DIRECTIONSGDirections n'a pas pu calculer d'itinéraire entre les points mentionnés dans la requète. Soit parce qu'il n'y a aucun itinéraire disponible entre les deux points, soit parce que nous ne disposons pas des données couvrant cette région.
(610) G_GEO_BAD_KEYLa clef indiquée est invalide ou n'est pas attribuée au domaine pour lequel elle a été donnée.
(620) G_GEO_TOO_MANY_QUERIESLe nombre de requètes, pour la clef donnée, a dépassé le quota des demandes autorisées pour une période de 24 heure.


La deuxième est un code de précision (de 1 à 8)
Si vous faite une demande sur une ville, sans nom de rue vous aurez une valeur plus faible que si vous demander aussi une rue












CodeDescription
0Localisation impossible.
1Niveau d'exactitude : Pays.
2Niveau d'exactitude : Région (état, province, préfecture, etc.).
3Niveau d'exactitude : Région secondaire(comté, municipalité, etc.).
4Niveau d'exactitude : Ville (ville, village).
5Niveau d'exactitude : Code (code postal).
6Niveau d'exactitude : Rue.
7Niveau d'exactitude : Intersection.
8Niveau d'exactitude : Adresse.


La troisième est la latitude
La dernière est la longitude

Une variante permet de récupérer une fichier xml. Il suffit de changer csv par xml dans la requete. On a alors quelques informations complémentaires
comme la région et le département.

dimanche 4 mai 2008

Les processeurs coldfire

La famille des processeurs coldfire a été conçue par motorola. Il s'agit d'une puce de type risc dont le jeu d'instruction est inspirée du 68000. D'ailleur le tout premier coldfire etait compatible avec le 68040. Les coldfires suivant contenaient un jeu d'instruction simplifié par rapport à l'original.

Il existe de nombreuses variantes de ce processeur. Le 5407 contient des périphériques de base comme des ports parallèles, séries et I2C. D'autres versions plus avancées contiennent des périphériques PCI, USB, ethernet et bus CAN. On trouve aussi de nombreux outils libres comme gcc ou le Coldfire Emulator. On peut aussi faire fonctionner linux dessus.

uCLinux et Coldfire

Coldfire Emulator

Le bus I2C

Le bus I2C ( Inter Integrated Circuit ) a été inventé par Philips semiconductors pour simplifier l'interconnection de dispositifs électroniques controlés par un micro-controleur. Son usage initial était les domaines de l'électronique grand public comme la télévision, la vidéo ou le son.

Il s'agit d'un bus série, ce qui explique que la partie électrique est très simple, puisque que l'on a un signal d'horloge et un signal données/adresses. Le nombre d'adresses est 127 ce qui semble peu, mais reste suffisant pour la plupart des applications.

De nos jours ce bus est présent dans les pc pour le contrôle de carte TV par exemple (le tuner). On le trouve aussi dans de nombreux micro-contrôleurs.

Télécharger des objets


Après le téléchargement de fichiers numériques, voici comment télécharger des objets physiques. Non, il ne s'agit pas d'une forme avancée de site de vente, qui viendrait vous livrer en moins de 30 minutes, mais d'un projet de université de Cornell pour la réalisation d'une imprimante 3D. L'aspect intérressant c'est que tous les plans et schémas de réalisation sont téléchargeables sur leur site en "open source". La documentation et les exemples de réalisations sont fournis.

à voir

fab@home

dimanche 6 avril 2008

Tableau blanc sur linux

Johnny Chung Lee a présenté il y a quelques temps un système de tableau blanc constitué d'un PC, un vidéo projecteur et une wiimote. Il utilise simplement le capteur infrarouge de la wiimote pour détecter la position d'un crayon électronique basé sur une simple LED infrarouge. L'exemple de programme qu'il donne est écrit en c# sur windows. Depuis une version basée sur linux est apparue. Elle utilise les librairies bluez et python xlib.
Pour lancer le programme il suffit d'executer la commande python whiteboard.py.

L'utilisation est triviale, puisque l'on commence par calibrer en cliquant avec le crayon infrarouge aux quatres coins de l'écran projeté. Une fois cette opération faite, le crayon se comporte comme une souris.

Les sources se trouvent sur http://sourceforge.net/projects/wiiwhiteboard/

Il existe un portage en java : http://www.uweschmidt.org/wiimote-whiteboard

En cas de problème avec la pile bluetooth il faut la réinitialiser en lançant la commande /etc/init.d/bluetooth restart

jeudi 3 avril 2008

Programmation USB sous linux

La carte k8055 de velleman est une carte d'interface usb dotée de 8 sorties numériques (bufferisées par un ULN2803), de 5 entrées numériques, de 2 entrées analogiques et de 2 sorties analogiques basées sur un générateur PWM. Le microcontroleur qui régente tout ça est un PIC 16C745.

Il existe un programme de commande sous linux qui m'a permis d'aller explorer la programmation USB sur ce système. Ce programme se base sur la librairie libusb qui remonte au niveau utilisateur les fonctions de gestion USB.

Les sources sont suffisaments documentés pour comprendre facilement comment cela fonctionne.

Pour en savoir plus :

Confusions

Je constate que bien souvent, dans la presse ou sur internet, la notion d'urbanisation s'accompagne de tout un tas de sigles du style SOA, BPM, BPEL, bus logiciels, webservices, business intelligence, etc....en fait représentant des technologies ou des notions purement liés à l'informatique. C'est oublier un peu vite, me semble t-il qu'un bon projet d'urbanisation doit commencer par décrire le métier pour lequel l'informaticien travaille. Quand je dis métier, ce n'est pas encore les spécifications fonctionnelles, mais bien le métier, c'est à dire ce que les autres gens font de leur journées pour gagner leur vie. Dans cet univers là, l'ordinateur n'existe pas, ce qui, j'en conviens peut paraitre suréaliste pour l'informaticien lambda.

Au départ il s'agit simplement de décrire le système d'information, c'est à dire quelles sont les informations manipulés par les gens du métier. Cela ne veut pas dire que toutes ces informations vont se retrouver dans un ordinateur. Il va falloir faire des choix en fonction de la faisabilité ou du coût (ou des deux).

C'est ensuite que l'on commence à parler de spécifications fonctionnelles, lorsque justement on sait ce qui va être informatisé ou sur ce qui l'est déjà. Quand j'emploi le futur, c'est aussi parce que dans le monde réel, les gens ont des projets, une entreprise peut faire des choix stratégiques. Il est important aussi de penser à cela, à l'évolution du métier.

Ce n'est qu'après cela que l'on peut commencer à se poser des questions liés au système informatique.

Les spécifications fonctionnelles ne doivent normalement contenir aucune notion d'informatique, ce n'est pas encore le moment. Ce n'est qu'une partie de la description du métier.


La notion de système informatique apparait vaguement avec

Embarquer

Non, ce billet ne concerne pas l'informatique embarqué, mais la sérieuse tendance de java à embarquer d'autres langages. Depuis la spec JSR223, l'univers des interpréteurs embarqués dans Java explose. En peut en effet faire fonctionner du javascript, groovy, php, python, ruby et donc aussi les frameworks qui vont avec, ce qui permet de voir la naissance de projets comme JRuby On Rail. Mais quel est donc l'intérêt de faire ceci ? Tous d'abord cela permet de bénéficier de la jvm et de la longue expérience d'optimisation et de compilation à la volée accumulée depuis 10 ans. Mais surtout cela permet de faciliter les phases d'intégration, voir d'urbanisation autour d'applications implémentées avec des langages différents. J2EE sait très bien faire. On peut par exemple ainsi avoir des sites commerciaux en php relié a des ERP écrit en java.

Tous cela ouvre des perspectives...

lundi 3 mars 2008

SIMCAD

Au début des années 90, la revue elektor a publié le schéma d'une carte à base de 80c31 facile à construire (CI simple face), destinée à faire de l'expérimentation. Elle était équipée d'une RAM de 32ko et d'une EPROM de 32ko contenant un minuscule moniteur permettant de connecter la carte à un PC via un port série.
La carte peut faire fonctionner le 8052AH Basic. Elle peut aussi programmer une eprom.
Le soft livré comprenait un assembleur et un soft de transfert. Tout est écrit en turbo pascal. J'ai pu le recompiler avec freepascal sous linux sans trop de modifications. La plus grosse partie des modifs concerne le port série et quelques unes sur le soft d'assemblage. En tout cas ma carte fonctionne toujours aussi bien après avoir pris la poussière pendant quelques années.

mardi 26 février 2008

L'ERP opensource vu par Apache

Les projets de la fondation Apache ont ceci de particulier que leur licence permet une grande permissivité et une grande possibilité d'intégration dans d'autre projets. Il existe un projet particulièrement intérressant qui est OfBiz. Il s'agit d'une librairie destinée à la réalisation de logiciels de gestion et de site de e-commerce. Elle a permis le lancement de nombreux projets d'ERP opens-source comme Neogia ou OpenTabs.

à voir :

OFBiz

OpenTabs

Neogia

Hello BCEL

Voici un autre exemple de programme autour de BCEL. Il s'agit d'un générateur de classe "Hello World". Ce programme instancie et appel ensuite la méthode qui va bien pour afficher le message "Hello World"


import org.apache.bcel.generic.*;
import org.apache.bcel.*;
import java.io.*;

public class FabriqueDeClasseHelloWorld implements Constants {
private InstructionFactory fabriquePourInstructions;
private ConstantPoolGen listeDesConstantesDeLaNouvelleClasse;
private ClassGen classeAConstruire;

// nom de la nouvelle classe à créer
static private String classNameTarget() {
return "HelloWorld3";
}

public FabriqueDeClasseHelloWorld() {
classeAConstruire = new ClassGen(classNameTarget(), "java.lang.Object",
classNameTarget()+".java", ACC_PUBLIC | ACC_SUPER, new String[] {});
listeDesConstantesDeLaNouvelleClasse = classeAConstruire
.getConstantPool();
fabriquePourInstructions = new InstructionFactory(classeAConstruire,
listeDesConstantesDeLaNouvelleClasse);
}

public void create(OutputStream out) throws IOException {
creationDuConstructeur();
creationMethodeMain();
classeAConstruire.getJavaClass().dump(out);
}

private void creationDuConstructeur() {
InstructionList il = new InstructionList();
MethodGen method = new MethodGen(ACC_PUBLIC, Type.VOID, Type.NO_ARGS,
new String[] {}, "", classNameTarget(), il,
listeDesConstantesDeLaNouvelleClasse);

InstructionHandle ih_0 = il.append(fabriquePourInstructions.createLoad(Type.OBJECT, 0));
System.out.println(ih_0.getInstruction().getName());

InstructionHandle ins2 = il.append(fabriquePourInstructions.createInvoke(
"java.lang.Object", "", Type.VOID, Type.NO_ARGS,
Constants.INVOKESPECIAL));
System.out.println(ins2.getInstruction().getName());

InstructionHandle ih_4 = il.append(fabriquePourInstructions.createReturn(Type.VOID));
System.out.println(ih_4.getInstruction().getName());

method.setMaxStack();
method.setMaxLocals();
classeAConstruire.addMethod(method.getMethod());
il.dispose();
}

private void creationMethodeMain() {
System.out.println("\nListe des instructions de la méthode main");
InstructionList il = new InstructionList();

// on rajoute une méthode main sans paramètre
MethodGen method = new MethodGen(ACC_PUBLIC | ACC_STATIC, Type.VOID,
Type.NO_ARGS, new String[] {}, "main", classNameTarget(), il,
listeDesConstantesDeLaNouvelleClasse);

InstructionHandle ins1 = il.append(fabriquePourInstructions.createFieldAccess(
"java.lang.System", "err",
new ObjectType("java.io.PrintStream"), Constants.GETSTATIC));

System.out.println(ins1.getInstruction().getName());

InstructionHandle ins2 = il.append(new PUSH(
listeDesConstantesDeLaNouvelleClasse,
"Hello world sur la sortie erreur!"));
System.out.println(ins2.getInstruction().getName());

InstructionHandle ins3 = il.append(fabriquePourInstructions.createInvoke(
"java.io.PrintStream", "println", Type.VOID,
new Type[] { Type.STRING }, Constants.INVOKEVIRTUAL));

System.out.println(ins3.getInstruction().getName());

InstructionHandle ins4 = il.append(fabriquePourInstructions.createReturn(Type.VOID));
System.out.println(ins4.getInstruction().getName());

method.setMaxStack();
method.setMaxLocals();
// on rajoute la nouvelle méthode à la classe
classeAConstruire.addMethod(method.getMethod());
il.dispose();
}

public static void main(String[] args) throws Exception {
FabriqueDeClasseHelloWorld creator = new FabriqueDeClasseHelloWorld();

// on doit avoir un répertoire build ou se trouve les .class fabriqués
creator.create(new FileOutputStream("build/" + classNameTarget()
+ ".class"));

/*
* attention, pour que cette partie fonctionne il faut que le répertoire
* build se trouve dans le classpath
*/

// on récupère la classe que l'on vient de créer
Class cls = Class.forName(classNameTarget());

// on fait une instance de cette classe
Object obj = cls.newInstance();

// l'unique méthode est le main. On fait un appel sur ce main
obj.getClass().getMethods()[0].invoke(obj);


}
}

lundi 25 février 2008

Hello Spring

Hello World Spring

Le framework Spring implémente le design pattern IoC (inversion de contrôle). Le petit exemple qui va suivre a pour but de donner un petit exemple simple d'utilisation de cette API.

Tout d'abord on souhaite réaliser une application qui affiche "Hello World". On souhaite que cette application soit le plus paramétrable possible. En fait elle doit permettre d'afficher "Hello World" sur une sortie quelconque.

Il s'agit donc de rendre la sortie générique.

La première implémentation se ferait à l'aide de deux classes :

Pour commencer, la classe application


package net.olivier_thebault;

import net.olivier_thebault.screen.Screen;

public class HelloWorld {

public Screen scr=new Screen();

public static void main(String[] args) {
HelloWorld helloWorld=new HelloWorld();
helloWorld.scr.show("Hello world !!!");
}

}


puis une classe d'affichage :


package net.olivier_thebault.screen;

public class Screen {

public void show(String text){
System.out.println(text);
}

}

Dans cet exemple, la classe application ne connait pas la méthode d'affichage, elle sait juste qu'il existe une classe Screen. Le problème est si l'on souhaite modifier la sortie, on doit créer une nouvelle classe d'affichage, NewScreen par exemple et modifier le programme principal en conséquence. Dans un cas simple, comme celui-ci, cela n'est pas très difficile, mais imaginons simplement, que l'on est plusieurs instances de Screen, donc plusieurs appels à new Screen(), la modification du programme serait alors beaucoup plus longue et accidentogène.
En plus ce ça il faudrait recompiler l'application.

Je vais alors faire une petite modification pour mieux séparer l'affichage du programme : rajouter une interface. En fait il s'agit d'établir un contrat entre la classe principale et la classe d'affichage. Cela aura pour avantage d'externaliser la liaison entre les deux classes

On obtient alors ceci pour l'interface :

package net.olivier_thebault;

public interface IScreen {

public abstract void show(String text);

}


et ceci pour les deux autres classes :


package net.olivier_thebault;

import net.olivier_thebault.screen.Screen;

public class HelloWorld {

public IScreen scr=new Screen();

public static void main(String[] args) {
HelloWorld helloWorld=new HelloWorld();
helloWorld.scr.show("Hello world !!!");
}

}



package net.olivier_thebault.screen;

import net.olivier_thebault.IScreen;

public class Screen implements IScreen {

/* (non-Javadoc)
* @see net.olivier_thebault.screen.IScreen#show(java.lang.String)
*/
public void show(String text){
System.out.println(text);
}

}



Cela va nous permettre d'externaliser complétement la référence à la classe Screen, en introduisant une nouvelle classe. Pour commencer le champ "scr" va être initialisé par le constructeur


package net.olivier_thebault;

public class HelloWorld {

public IScreen scr;

public void hello(){
scr.show("Hello world !!!");
}

public HelloWorld(IScreen scr){
this.scr = scr;
}

}


De fait il n'existe plus aucune référence au constructeur et à la classe Screen. De plus cette classe ne sera plus la classe principale du programme, elle perd sa méthode main au profit d'une méthode Hello

La classe principale sera désormais :


package net.olivier_thebault;

import net.olivier_thebault.screen.Screen;

public class HelloMain {

public static void main(String[] args) {
HelloWorld helloWorld=new HelloWorld(new Screen());
helloWorld.hello();
}

}


D'accord, tout ce qui est fait pour le moment est de déplacer le problème vers une nouvelle classe, ce qui a tendance à complexifier la solution, qui en plus est partielle. Il est donc temps d'améliorer et simplifier tout ça. C'est à que Spring peut rendre les choses plus confortable. Pour commencer il faut créer un fichier de configuration dont le rôle est de préciser quel est l'instance à passer à HelloWorld au moment de sa construction.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

<bean id="Hello" class="net.olivier_thebault.HelloWorld">
<constructor-arg>
<bean class="net.olivier_thebault.screen.Screen" />
</constructor-arg>
</bean>

</beans>


L'important ici se situe dans la balise bean. Id précise le nom que spring va donner à la classe. Ce nom va servir ensuite au moment de l'appel au constructeur. On précise ensuite, grace à la balise "constructor-arg" la classe implémentant l'interface IScreen. Spring va automatiquement créer l'instance qui va bien. C'est ici que l'on trouve le seul lien entre l'application et la classe d'affichage. Ce qui veut dire que l'on peut modifier l'application uniquement par paramétrage sans recompiler.


Le programme principal devient alors ceci :


package net.olivier_thebault;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;

public class HelloSpring {

public static void main(String[] args) {
// on récupère le fichier de configuration
Resource is = new FileSystemResource("config.xml");

// à partir du fichier de config on récupère une factory qui va permettre de construire
// les beans.
BeanFactory factory = new XmlBeanFactory(is);

// Le constructeur passe par spring
HelloWorld hello=(HelloWorld)factory.getBean("Hello");

hello.hello();
}

}



Voici donc un petit exemple d'Ioc via Spring. Spring permet de faire beaucoup plus de choses, de gérer les singletons, les transactions ou de créer des applications selon le modèle MVC. Il peut aussi s'interfacer avec struts ou hibernate.