Tutoriel de Data Flow Generator V0

De Wikip
Version : 1.36.1 4938 (2026-07-24) 20260724190824

Data Flow Generator (Dfg) est un outil qui a pour but le développement de logiciels en gardant la synchronisation entre les sources (Python et C++) et les modèles utilisant DfgUml(UML) et DfgBehaviour(code Python des méthodes).

Il fait appel aux paradigmes de développement suivants : Round-trip engineering, Object-oriented programming et Model-driven software development.

Dfg offre aussi la possibilité d'écrire ou lire automatiquement la forme persistante des données décrites dans DfgUml.

Il existe deux versions de Dfg : V0 et V1.

Dfg V1 utilise DfgUml et DfgBehaviour et ne génère pour l'instant que du code Python tandis que Dfg V0 n'utilise que DfgUml et génère du code Python et C++.

Dfg V1 peut aussi importer DfgUml depuis les diagrammes de classes contenus dans le fichiers édités par le logiciel Dia.

L'outil est gratuitement utilisable en ligne sur Internet à l'adresse http://dfg.bht.fr pour la version 0 et sur http://dfg1.bht.fr pour la version 1.

Les sources générés par Dfg suivent sous la licence MPL 1.1 et/ou LPGL

Data Flow Generator (Dfg) is a tool that is intended for software development by keeping the synchronization between the sources (PYTHON and C++) and models using DfgUml (UML) and DfgBehaviour (Python codes of methods).

It uses the following paradigms of development: Round-trip engineering, Object-oriented programming and Model-driven software development.

Dfg also offers the ability to automatically read and write the persistent form of data described by DfgUml.

There are two versions of Dfg: V0 and V1.

Dfg V1 uses DfgUml and DfgBehaviour and generates, currently, only Python code while Dfg V0 uses only DfgUml and generates Python and C++ code.

Dfg V1 can also import DfgUml from class diagrams contained in the files edited by the software Dia.

The tool can be used online for free at http://dfg.bht.fr for version 0 and http://dfg1.bht.fr for version 1.

Sources generated by Dfg ar under the license MPL 1.1 and/or LPGL
Dfg1.png
Fig. n°1: Data Flow Generator V1

1 Tuto_002 : Développement en c++ sous LINUX

1.1 L'objectif

L'objectif est de montrer comment créer rapidement un driver en c++ pour écrire/lire dans/depuis un fichier au format xml dont les données sont modélisées par le diagramme suivant :

1.2 Pour commencer

Pour commencer créer les répertoires tuto_002/ myXercesTools et utilities dans un répertoire commun dans lesquels nous allons travailler. Pour ceci tapez :

mkdir tuto_002 
mkdir myXercesTools
mkdir utilities
mkdir tuto_002/generated
mkdir tuto_002/generated_out

Vous aurez alors :

├── myXercesTools
├── tuto_002
│   ├── generated
│   └── generated_out
└── utilities

1.3 Le modèle

Le modèle utilisé par DataFlowGenerator correspondant au modèle uml précédent est le suivant :

<?xml version="1.0" encoding="UTF-8"?>
<grammar type="xml" version="1.0.0" FileFormatVersion="1.0.0">
    <el name="dessin" type="CDessin">
        <el name="base" type="CBase"  OnlyDefinition="1">
        </el>
        <el name="point" type="CPoint"  heritances="CBase"  OnlyDefinition="1">
            <el name="x" type="float"/>
            <el name="y" type="float"/>
        </el>
        <el name="segment" type="CSegment"  heritances="CBase"  OnlyDefinition="1">
            <el name="A" type="@CPoint"/>
            <el name="B" type="@CPoint"/>
        </el>
        <el name="cercle" type="CCercle"  heritances="CBase"  OnlyDefinition="1">
            <el name="C" type="@CPoint"/>
            <el name="R" type="float"/>
        </el>
        <el name="compound" type="CCompound" cardinality="*"  heritances="CBase">
            <el name="elements" type="@CBase" cardinality="*"
           accept="CPoint:CSegment:CCercle:CCompound"/>
        </el>
    </el>
</grammar>

Sur le site http://dfg.bht.fr, copiez ce modèle dans le champ de texte nommé grammar_file_name et dans le champ de texte nommé data_name écrivez "tuto_002_".

Sélectionnez Générer du c++ avec Xerces et puis cliquez sur le bouton Générer pour créer les fichiers suivants :

  • Les variables :
    • tuto_002_XMLDriver_pkg_version.h
    • tuto_002_XMLDriver.h
    • tuto_002_XMLDriver.cxx
  • Les fixes
    • my_xerces_impl.h
    • my_xerces_impl.cxx
    • utilities.h
    • utilities.cxx

Copier ces fichiers dans les répertoires myXercesTools, utilities et tuto_002/generated :

.
├── myXercesTools
│   ├── my_xerces_impl.cxx
│   └── my_xerces_impl.h
├── tuto_002
│   ├── generated
│      ├── tuto_002_XMLDriver.cxx
│      ├── tuto_002_XMLDriver.h
│      └── tuto_002_XMLDriver_pkg_version.h
└── utilities
    ├── utilities.cxx
    └── utilities.h

1.4 Compilation

1.4.1 Si XERCES 2.7 n'est pas installé sur votre système

Les sources de XERCES peuvent être téléchargées sous la forme de fichier nommé xerces-c-src_2_7_0.tar.gz depuis le site de archive.apache.org/dist/xml/xerces-c/Xerces-C_2_7_0/source/.

En notant <install_bin_dir> le répertoire dans lequel sera installée XERCES et <install_src_dir> le répertoire à partir duquel l'installation est réalisée, les opérations suivantes permettent l'installation :

1 mkdir <span style="border-color:#606060;border-radius:0.4em;border-style:solid;border-width:1pt;min-height:1em;padding-left:0.5em;padding-right:0.5em;background:#404060;color:#FFFFFF;"><install_bin_dir></span>/xerces-c-lib_2_7_0
 2 export <span style="border-color:#606060;border-radius:0.4em;border-style:solid;border-width:1pt;min-height:1em;padding-left:0.5em;padding-right:0.5em;background:#404060;color:#FFFFFF;">XERCESCROOT</span>=<install_src_dir>
 3 cd <span style="border-color:#606060;border-radius:0.4em;border-style:solid;border-width:1pt;min-height:1em;padding-left:0.5em;padding-right:0.5em;background:#404060;color:#FFFFFF;"><install_src_dir></span>/src/xercesc
 4 autoconf
 5 ./runConfigure -plinux -P <span style="border-color:#606060;border-radius:0.4em;border-style:solid;border-width:1pt;min-height:1em;padding-left:0.5em;padding-right:0.5em;background:#404060;color:#FFFFFF;"><install_bin_dir></span>
 6 make
 7 make install

1.4.2 Le programme tuto_002

Maintenant la variable XERCESCROOT doit être positionné sur le librairie XERCES installé donc cette fois-ci :

export XERCESCROOT=<install_bin_dir>

par exemple :

export XERCESCROOT=/local01/atoross/exe/xerces-c-lib_2_7_0

Afin de pouvoir exécuter le programme compilé il faut aussi modifier LD_LIBRARY_PATH comme suit :

export LD_LIBRARY_PATH=$XERCESCROOT/lib:$LD_LIBRARY_PATH

Le répertoire XERCESCROOT doit contenir les répertoires :

.
├── include
└── lib

Créer un fichier nommé "Makefile" dans le répertoire tuto_002 et copier le texte suivant dans ce fichier :

proj=tuto_002
all : test

test : ${proj} 
	
${proj} : util.o myxerces.o xmldriver.o  main.cpp     	
	g++ -I${XERCESCROOT}/include -I../utilities  -Igenerated -I../myXercesTools -L${XERCESCROOT}/lib  -lxerces-c    main.cpp util.o myxerces.o xmldriver.o -o ${proj}
	
util.o	: ../utilities/utilities.cxx  ../utilities/utilities.h
	g++ -I../utilities ../utilities/utilities.cxx  -c -o util.o

xmldriver.o :generated/$(proj)_XMLDriver.cxx  generated/$(proj)_XMLDriver.h generated/$(proj)_XMLDriver_pkg_version.h
	echo "g++ -I${XERCESCROOT}/include -I../utilities -I../myXercesTools  -Igenerated  -L${XERCESCROOT}/lib   generated/${proj}_XMLDriver.cxx -c -o xmldriver.o"
	g++ -I${XERCESCROOT}/include -I../utilities -I../myXercesTools  -Igenerated  -L${XERCESCROOT}/lib   generated/${proj}_XMLDriver.cxx -c -o xmldriver.o

myxerces.o:   ../myXercesTools/my_xerces_impl.cxx ../myXercesTools/my_xerces_impl.h
	echo "g++ -I../utilities -I../myXercesTools -I${XERCESCROOT}/include -L${XERCESCROOT}/lib    ../myXercesTools/my_xerces_impl.cxx -c -o myxerces.o"
	g++ -I../utilities -I../myXercesTools -I${XERCESCROOT}/include -L${XERCESCROOT}/lib    ../myXercesTools/my_xerces_impl.cxx -c -o myxerces.o
clean :
	-rm *.o *~ ${proj} ./generated_out/*

Les sources du programme doivent être écrite dans le fichier nommé "main.cpp" et créé dans tuto_002, copier ces sources depuis le paragraphe "le programme complet" dans ce fichier. Nous avons maintenant les fichiers suivants :

.
├── myXercesTools
│   ├── my_xerces_impl.cxx
│   └── my_xerces_impl.h
├── tuto_002
│   ├── generated
│   │   ├── tuto_002_XMLDriver.cxx
│   │   ├── tuto_002_XMLDriver.h
│   │   └── tuto_002_XMLDriver_pkg_version.h
│   ├── generated_out
│   ├── main.cpp
│   ├── Makefile
└── utilities
    ├── utilities.cxx
    └── utilities.h

Pour compiler entrer dans le répertoire tuto_002 et tapez :

make

Pour exécuter le programme entrer dans le répertoire tuto_002 et tapez :

./tuto_002

Vous verrez alors aparaître le fichiers :

generated_out/
├── dessin1.xml
└── dessin2.xml

1.5 Explication des sources

1.5.1 Extension, utilisation de la fabrique

Avoir des données sans pouvoir ajouter des traitements ou extensions ce n'est pas très intéressant. Pour étendre les classes générées on utilise l' héritage et le polymorphisme des classes. Afin de pouvoir utiliser les nouveaux types de classe on utilise un fabrique qui est un singleton.

Par exemple si nous voulions ajouter un traitement aux cercle, une translation, on peut écrire le code suivant :

class myCCercle : public CCercle
{
public :
    int my_attr ;
    myCCercle() : CCercle(), my_attr(0)
    {
    } ;
    void move( double dx, double dy )
    {
        C->x = C->x+dx ;
        C->y = C->y+dy ;
    }  
};
CDessinBase * myCCercle_factory()
{
    return  new myCCercle() ;
};

Mais il ne faut pas oublier d'enregistrer cette classe dans la fabrique, voici comment le faire :

CDessinBase_factory::instance()->register_creator( "CCercle", myCCercle_factory ) ;

Pour créer la classe il suffit d'appeler la fabrique :

CCercle * cercle =  (CCercle *) factory->create( "CCercle" ) ;

Voici l'exemple qui montre comment appliquer le translation :

myCCercle* mycercle = (myCCercle*) cercle ;
mycercle->move( 10.0, 10.0 ) ;

1.5.2 Construction des données

La construction se fait en appelant la fabrique. Pour les structures ayant une cardinal diffèrent de 1 nous utilisons les vecteur de la librairie STL. Exemple :

CDessinBase_factory * factory =CDessinBase_factory::instance();

...

CDessin * Med = (CDessin *) factory->create( "CDessin" ) ;
CCompound * comp =  (CCompound *) factory->create( "CCompound" ) ;
Med->compound.push_back( comp ) ;
Rq La mémoire allouée est libérée par le code généré

1.5.3 Charger et décharger

En utilisant une instance de CFileFormatInfo nous pouvons sauvegarder ou charger tout fichier contenant les données conforme au modèle.

CFileFormatInfo Info ;
Info.Save2XMLFile( Med , "generated_out/dessin1.xml" ) ;

CDessin * Med2 = Info.LoadFromXMLFile( "generated_out/dessin1.xml" ) ;
Info.Save2XMLFile( Med2 , "generated_out/dessin2.xml" ) ;
Rq La classe CFileFormatInfo cache bon nombre d'initialisations XERCES.

1.5.4 Le programme complet

#include "generated/tuto_002_XMLDriver.h"
#include <iostream>
#include <typeinfo>
using namespace tuto_002_XMLDriver_ns ;

class myCCercle : public CCercle
{
public :
    int my_attr ;
    myCCercle() : CCercle(), my_attr(0)
    {
    } ;
    void move( double dx, double dy )
    {
        C->x = C->x+dx ;
        C->y = C->y+dy ;
    }  
};

CDessinBase * myCCercle_factory()
{
    return  new myCCercle() ;
};
 
int main(int argc, char * argv[ ])
{
    std::cout << "start" << std::endl ;
    
    //enregistrement du créateur
    CDessinBase_factory::instance()->register_creator( "CCercle", myCCercle_factory ) ;
        
    
    // Instance sur la fabrique de classe
    CDessinBase_factory * factory =CDessinBase_factory::instance();

    // Créaton dans la mémoire
    CDessin * Med = (CDessin *) factory->create( "CDessin" ) ;
    CCompound * comp =  (CCompound *) factory->create( "CCompound" ) ;
    Med->compound.push_back( comp ) ;

    CCercle * cercle =  (CCercle *) factory->create( "CCercle" ) ;
    cercle->C->x = 12.0 ;
    cercle->C->x = 3.0 ;
    cercle->R = 40.0 ;
    comp->elements.push_back( (CBase *) cercle  ) ;

    CSegment * segment =  (CSegment *) factory->create( "CSegment" ) ;
    segment->A->x = 5.0 ;
    segment->A->y = 6.0 ;
    segment->B->x = 1.0 ;
    segment->B->y = -2.0 ;
    comp->elements.push_back( (CBase *) segment  ) ;

    CCompound * comp2 =  (CCompound *) factory->create( "CCompound" ) ;
    comp->elements.push_back( (CBase *) comp2  ) ;
    cercle =  (CCercle *) factory->create( "CCercle" ) ;
    cercle->C->x = 16.0 ;
    cercle->C->x = 7.0 ;
    cercle->R = 30.0 ;
    comp2->elements.push_back( (CBase *) cercle  ) ;

    comp = comp2 ;

    comp2 =  (CCompound *) factory->create( "CCompound" ) ;
    comp->elements.push_back( (CBase *) comp2  ) ;
    cercle =  (CCercle *) factory->create( "CCercle" ) ;
    cercle->C->x = 13.0 ;
    cercle->C->x = 4.0 ;
    cercle->R = 20.0 ;
    comp2->elements.push_back( (CBase *) cercle  ) ;

    comp =  (CCompound *) factory->create( "CCompound" ) ;
    Med->compound.push_back( comp ) ;
    comp->copy( comp2 ) ;

    myCCercle* mycercle = (myCCercle*) cercle ;
    mycercle->move( 10.0, 10.0 ) ;

    try
    {
        CFileFormatInfo Info ;
        Info.Save2XMLFile( Med , "generated_out/dessin1.xml" ) ;

        CDessin * Med2 = Info.LoadFromXMLFile( "generated_out/dessin1.xml" ) ;
        Info.Save2XMLFile( Med2 , "generated_out/dessin2.xml" ) ;
    }
    catch (const my_xerces::myXercesError& toCatch)
    {
        std::cerr << toCatch.what() << std::endl ;
    }
    Med->clear() ;
    delete Med ;

    std::cout << "end" << std::endl ;
    return 0 ;
}

2 Voir aussi