Affichage des articles dont le libellé est java. Afficher tous les articles
Affichage des articles dont le libellé est java. Afficher tous les articles

mercredi 28 août 2019

Exemple d’utilisation d’Apache Freemarker : Génération du code

Pourquoi générer du code Java

Java est relativement lourd comme langage; il est très strict mais très efficace. Des fois, on n’a pas le temps (ou ils suffit être comme moi, un peu féniant) pour tout écrire, alors, on fait appel à nos outils pour générer une partie du code. A ce niveau, les différents IDE possèdent tous des outils pour générer les constructeurs et les Setters et Getters et bien d’autres parties de nos classes Java.
Dans cet exemple, je vais compter sur un "template engine" pour générer le code des Java Beans. J’ai choisi comme exemple Apache Freemarker. Je n’ai aucune idée sur les autres "template engines".

Apache Freemarker

Je reprends le diagramme donné par Apache pour expliquer le principe d’un "template engine" :



ce qui est important à noter est l’affirmation ( ici ):

Anything not an FTL tag or an interpolation or comment is considered
static text and will not be interpreted by FreeMarker; it is just
printed to the output as-is.

Par conséquent, Freemarker peut être utilisé pour générer n’importe quel format texte.

L’exemple

Dans cet exemple, j’ai tenté de générer le code d’un Java Bean.

La spécification JavaBeans de Oracle définit les composants de type
JavaBeans comme « des composants logiciels réutilisables manipulables
visuellement dans un outil de conception ».

Ils sont utilisés pour encapsuler plusieurs objets dans un seul objet :
le « bean » (ou haricot en français). Le « bean » regroupe alors tous
les attributs des objets encapsulés, et peut définir d'autres attributs
si besoin. Ainsi, il représente une entité plus globale que les objets
encapsulés de manière à répondre à un besoin métier.

Pour cela, j’ai défini deux classes comme modèle :

public class Variable {

    String variableName;
    String variableType;

}

Et

public class Bean {

    public String beanName;
    public List<Variable> attributes;

}

Ainsi, un Bean peut être créé facilement. A titre d’exemple, si je veux un Bean "User" avec trois attributs : id, userName et password, il suffit un petit bout de code comme le suivant :

Bean user = new Bean();
user.setBeanName("User");
user.setAttributes(new ArrayList<>());
user.getAttributes().add(new Variable("id", "int"));
user.getAttributes().add(new Variable("userName", "String"));
user.getAttributes().add(new Variable("password", "String"));

Par la suite, il fallait créer une petite template avec un constructeur vide et l’ensemble des Setters et Getters :

public class ${bean.beanName} {

 public ${bean.beanName}(){
 }

<#list bean.attributes as attribut>;
 ${attribut.variableType} ${attribut.variableName};

 public void set${attribut.variableName?cap_first}(${attribut.variableType} value){
  ${attribut.variableName} = value;
 }

 public ${attribut.variableType} get${attribut.variableName?cap_first}(){
  return ${attribut.variableName};
 }

</#list>
}

Par la suite, il ne reste qu’jouter le Bean au modèle, puis passer ce dernier à la template chargé pour générer le code nécessaire :

public static void createBean(Configuration cfg, String templateName, Bean bean) throws MalformedTemplateNameException, TemplateException, ParseException, IOException{

        Map root = new HashMap();
        root.put("bean", bean);
        Template template = cfg.getTemplate(templateName);
        Writer out = new OutputStreamWriter(new  FileOutputStream(new File(bean.getBeanName() + ".java")));
        template.process(root, out);

}

Le résultat est bien le fichier source attendu pour le Bean décrit.

En effet, l’outil est très simple à utiliser au point où je me suis amusé à ajouter une template qui génère une fenêtre avec les champs nécessaires. La tâche est loin d’être finie (adapter les champs de saisi selon les types de données), mais le début était très simple.

Vous pouvez trouver le code exemple ici.
Vous pouvez trouver la version PDF de ce post ici.

samedi 24 août 2019

Nitrite, un petit SGBD NoSQL : l'équivalent de Sqlite pour le NoSQL

Le NoSQL "désigne une famille de systèmes de gestion de base de données (SGBD) qui s'écarte du paradigme classique des bases relationnelles. L'explicitation du terme la plus populaire de l'acronyme est Not only SQL (« pas seulement SQL » en anglais) même si cette interprétation peut être discutée" (Wikipedia)

Le non respect du paradigme traditionnel veut dire, principalement, le non respect des formes normales et plus particulièrement la première forme normale, ainsi, une propriété peut avoir plusieurs valeurs à un instant donné (tableau de valeurs simples et/ou être composée). L'objectif n'est pas la composition, autrement, les SGBD Objets deviendraient suffisants. L'objectif est d'éviter l'opération de jointure.

Par exemple, si nous possédons trois tables :

  • Utilisateur : qui compte 10.000 enregistrements (lignes),
  • Lien_Amitie : qui compte  1.000.000 d'enregistrements (chaque utilisateur possède 100 amis en moyenne),
  • Publication : qui compte 10.000.000 enregistrements (1.000 publications per utilisateur en moyenne)
Pour afficher le fil d'actualité, il faut faire une jointure entre Utilisateur et Lien_Amitie pour trouver les amis et une jointure entre Lien_Amitite et Publication pour récupérer les publications des amis. Sur des fichiers de cette taille, les requêtes deviendront très vite coûteuses en temps d'exécution. Imaginez maintenant des systèmes avec 1 million, 10 millions ou 100 millions d'utilisateurs.

Néanmoins, la plus part des SGBD NoSQL sont conçus pour supporter une grande quantité de données, ainsi, le passage d'un modèle conceptuel qui cite "table", "propriété", "association", "clé" se trouve face à des termes comme "cluster", "noeud", "réplication" et d'autres notions relatives au "big data". Par conséquent, ils ne sont pas adapté à des applications de petite taille (mono utilisateur, mobile, etc.).

La solution peut être Nitrite (NoSQL Object -> NO2) : l'équivalent du Sqlite dans le monde NoSQL. Il s'agit un SGBD NoSQL de petite taille. Son noyau permet de faire les opérations de base CRUD. Nitrite est doté aussi d'un ensemble d'outils qui permettent son extension pour supporter plusieurs langages, la réplication des données, la visualisation des données et autres.

J'ai testé Nitrite en suivant son manuel d'utilisation. L'objectif était de créer une seule Collection (l'équivalent d'une table) pour stocker un seul type d'objets (une seule classe dans le modèle de données). J'ai essayé de créer deux projets :

  • Un projet Maven tel que recommandé par l'auteur : un premier teste rapide dans lequel je ne m'attendais pas d'avoir des problèmes et effectivement, le teste a passé sans problèmes.

  • Un projet ordinaire (sans passer par Maven) : l'idée est de voir à quel point c'est simle d'ajouter Nitrite à projet existant.

Après, le teste je peux résumer on avis en points forts et faibles :

Points forts


  • Documentation claire : la documentation est disponible, des fois au format AsciiDoc, et, à mon avis, elle est suffisante pour apprendre les bases.
  • L'outil tient sa promesse : il est simple, rapide en développement, le nommage des fonctions et des classes est très efficace et très parlant.
  • Une classe de Collection générique est déjà disponible et permet de cacher les notions internes telles que la notion du Document ce qui facilite encore l'apprentissage et l'utilisation de l'outil.

Points faibles

  • L'utilisation de Maven est (presque) obligatoire : même avec un temps de construction d'environ 1 minute et 34 secondes, l'autre option (gérer les dépendances manuellement) est (presque) impossible. La plus part des dépendances de Nitrite sont à leur tour des projets Maven sur GitHub, ainsi, il faut les télécharger et les construire manuellement.

  • Le nombre de dépendances : à mon avis, avoir un grand nombre de dépendances ne peut qu'être un inconvénient majeur. En plus, la plus part de ces dépendances ne sont pas supportés par des fondations ou des entreprises, ainsi, si une de ces dépendances est abandonnée, on est obligé de continuer sa maintenance au niveau local. Sur ce point, je trouve SmallSQL plus avantageux.
  • L'outil ne supporte pas le langage SQL : malgré que, par définition, ce n'est pas nécessaire, p)lsuieurs SGBD NoSQL ajoute le support du (ou d'une partie du) langage SQL pour faciliter l'interrogation. Malheureusement, ce n'est pas le cas de Nitrite.
Finalement, je conseille tout intéressé par les SGBD NoSQL de jeter un coup d'oeil sur Nitrite et de voir les possibilités qu'il offre.

Vous pouvez trouver une version PDF de ce post ici.

jeudi 28 février 2019

De la génération du code à la génération des applications (2/3) : la génération du code

La génération du code est le point fort des EDI. Ces dernier vise à traduire des actions visuelles pour générer un code correct. Cela s'ajout à un ensemble d'outil de gestion des projets et d'édition du code (coloration, auto-complétion, etc.) (point discuté ici).
Dans cet exemple, je vais illustrer cette caractéristique principal des EDI. Pour faire, il n'y a pas mieux que travailler sur des composants graphiques où l'action visuelle est plus parlante. Ainsi, je vais commencer par créer un nouveau projet et par créer une JFrame. Je vais garder en esprit que NetBeans "génère automatiquement" une méthode main pour chaque JFrame.




NetBeans utilise GroupLayoutManager comme LayoutManager par défaut pour gérer le positionnement des éléments. Cela nous donne l'avantage pour gérer d'une façon très souple le positionnement des éléments, néanmoins, cela limite la portabilité de notre code pour d'autres éditeurs.
Ajoutons quelques composants pour voir le code généré :


L'outil nous permet de voir et de modifier toutes les propriétés des composants manipulés. Il nous donne aussi la possibilité de changer des éléments basiques du génération du code tels que les nomes des variables :


Jetons un coup d'oeil sur le code généré :

    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        lblMessage = new javax.swing.JLabel();
        txtMessage = new javax.swing.JTextField();
        btnDisplay = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        lblMessage.setText("Message : ");

        txtMessage.setText("Message to display");

        btnDisplay.setText("Diplay");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(85, 85, 85)
                        .addComponent(lblMessage)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(txtMessage, javax.swing.GroupLayout.PREFERRED_SIZE, 155, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(161, 161, 161)
                        .addComponent(btnDisplay)))
                .addContainerGap(71, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(53, 53, 53)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(lblMessage)
                    .addComponent(txtMessage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(30, 30, 30)
                .addComponent(btnDisplay)
                .addContainerGap(173, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>

Nous voyons que le code généré est un peu lourd, c'est à cause de LayoutManager utilisé.
Nous pouvons changer le LayoutManager en toute simplicité et sans modifier le code directement. Il suffit de faire un clique droit sur l'objet de la JFrame dans le navigateur et de choisir le nouveau LayoutManager de la liste qui s'affiche en pointant "Set Layout" :


Revenant à notre code :

    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        lblMessage = new javax.swing.JLabel();
        txtMessage = new javax.swing.JTextField();
        btnDisplay = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        getContentPane().setLayout(null);

        lblMessage.setText("Message : ");
        getContentPane().add(lblMessage);
        lblMessage.setBounds(85, 55, 77, 15);

        txtMessage.setText("Message to display");
        getContentPane().add(txtMessage);
        txtMessage.setBounds(174, 53, 155, 19);

        btnDisplay.setText("Diplay");
        getContentPane().add(btnDisplay);
        btnDisplay.setBounds(161, 102, 78, 25);

        pack();
    }// </editor-fold>  

Ainsi, nous pouvons contrôler facilement le code généré à un niveau très bas et avec toute la liberté, mais, un certain niveau de connaissance et de compréhension du code généré est nécessaire.


lundi 24 septembre 2018

[En Deux Mots] Ne faites pas de longues ruptures

Même si ce conseil paraît évident, j'ai fait cette erreur de ne pas le suivre. J'ai pris une longue rupture qui a atteint les 3 ans, durant lesquelles, je n'ai pas réalisé des projets complets. Mon travail de développement se limitait à ce que j'avais besoin pour assurer les Travaux Pratiques en Algorithmique (pour les étudiants en première année Mathématique et Informatique - MI). Deux ans en Pascal et une dernière année en C.
La cause principale de ce désastre était mes débuts en doctorat. entamer un nouveau domaine n'est pas toujours une chose facile, surtout s'il s'agit d'un domaine loin de l'informatique. Je me trouvais étudier les livres de psychologie, psychopédagogie, psychologie du développement, théorie de l'action et les théories des émotions.

Sloman, A. (2004, March). What are emotion theories about. In Invited talk at cross-disciplinary workshop on Architectures for Modeling Emotion at the AAAI Spring Symposium at Stanford University in March.

Les résultats de cette rupture étaient catastrophiques. Premièrement, mes productions étaient des codes dispersés qui visaient des exercices d'introduction à l'algorithmique, des exemples sur les boucles et quelques exercices très classiques comme la vérification d'une grille Sudoku ou bien trouver les nombres amis. Si mes participations sur les forums des débutants ont devenus plus détaillées et plus pédagogiques, mes participations sur les forums plus avancés commençaient à diminuer avant de s'arrêter complètement. Mon repository sur Source Forge a stagné complètement aussi.
Deuxièmement, je n'ai pas pu suivre du près les nouvelles approches révolutionnaires qui ont vu le jour durant ces années. Groovy était un langage des amateur, Docker était dans ces débuts et semblait avancé un peu doucement et l'école fonctionnelle semblait encore endormie. Après trois ans, Groovy n'est plus le langage pour les amateurs; il est devenu un langage et une plateforme très intéressante. Je ne pouvait même pas reconnaître des parties telles que Grail qui a changé complètement. Docker a aussi changé, maintenant, il est doté d'un écosystème complet et il est devenu la base d'autres plateformes telles que Fn. Cette dernière prouvait qu'une l'approche fonctionnelle est du retour et avec puissance; l'approche Objet sur laquelle je me basais complètement a commencé à montrer sa lourdeur sur le côté serveur.
Finalement, je ne reconnaissais plus ma plateforme préférée : Java (J2SE/J2EE). La J2EE 6 était une vrai révolution, les fichiers XML que j'ai tant utilisé ne sont plus nécessaires et ils sont généré automatiquement à partir des annotations. Les services web RESTful ont devenus plus simples et plus rapides à développer. Les annotations se multipliaient et les outils aussi. Java 8 et les expressions Lambda ont été introduites, je n'en savait rien sauf quelques articles très brefs que j'ai lus.
Comment je me suis réveillé ? Je préparé une formation Java pour des étudiants. C'était avant l'introduction du module Programmation Orientée Objet avec des Travaux Pratiques en Java. Tout simplement, j'ai trouvé du mal à écrire ma fonction main, c'était aussi grave. Durant les deux années suivantes, j'ai essayé de récupéré. Même si je me débrouille pas mal, je pense que tout ce la était facile à éviter si je ne me suis pas émergé complètement dans mon doctorat et mon enseignement.
Alors, Ne prenez jamais de longues vacances et ne faites jamais de grandes ruptures. Restez près de votre éditeurs et travaillez sur des projets, même les plus simples, d'une manière continue. Ne vous contentez pas des articles, installez les nouvelles versions et essayez les, ce n'est pas une perte du temps, c'est même un gain du temps.
(Pourquoi cet article ? Jetez un coup d’œil par ici)

samedi 16 décembre 2017

LazySloth : un outil pour générer rapidement des JavaBeans

Dans un article précédent (ici), j'ai encouragé l'idée de développer et de construire sa propre boite à outils pour réaliser des tâches répétitives ou ennuyeuses, même, si l'outil en question ne sera pas utilisé par d'autres personnes. L'outil peut être un script, un programme ou un (mini) (micro) logiciel qui fait une seule chose.

Le fait qu'il ne sera pas utilisé par d'autres personnes possède un côté positif. Il n'est plus nécessaire de bien documenter le code, respecter les modèles sophistiqués ou utiliser la dernière technologie. Il n'est plus nécessaire de contrôler toutes les données ou bien de corriger tous les bugs. C'est votre propre outil et vous connaissez ses points faibles.

Dans cet article, je veux présenter l'un de mes outils préférés : LazySloth. Comme son nom l'indique, je l'ai créé parce que je suis un peu "fainéant". Vu que je travaille souvent sur des diagrammes de classes ou bien des diagrammes Entité/Association, cet outil me permet de traduire rapidement ce diagramme vers des classes Java (JavaBeans) et des scripts SQL pour créer les tables adéquates.

L'idée est de faire le tout en une seule commande dans la ligne de commande. Cette commande est constituée de trois partie :

1. Qu'est ce qu'on veut générer :
    a. -java : pour générer des classes Java seulement.
    b. -sql : pour générer des script SQL seulement.
    c. -both : pour générer les classes Java et les scripts SQL.

2. Le nom de la classe ou de l'entité qu'on veut traduire vers Java et SQL.

3. La liste des colonnes séparées par des espaces. La première lettre désigne le type de la colonne, elle ne sera pas prise comme partie de son nom. Les types des données supportés sont les types que j'utilise personnellement dans les différents exemples :
    a. i : pour Integer, pour stocker des entiers.
    b. n : pour Numeric, pour stocker les nombres réelles.
    c. d : pour Date, pour stocker des dates.
    d. s : pour String, pour stocker des chaînes de caractères. C'est le type désigné par défaut si l'outil n'arrive pas à déterminer un type à partir de la première lettre de la colonne.

Il est possible d'ajouter des contraintes après le nom de la colonne. Elles doivent être séparées par des ":" pour ne pas les confondre avec le nom de la colonne. Les contraintes supportées pour le moment :
  1. pk : pour désigner la colonne comme clé primaire.
  2. sN : (exemple s20) pour spécifier N (20 dans l'exemple) comme taille de la chaîne de caractères.
  3. a : pour désigner la colonne comme AUTO_INCREMENT.

Exemples :

Si la commande ne donne pas toutes les informations nécessaires, l'aide de l'outil est affiché :

java -jar LazySloth.jar



Une commande très simple consiste à créer une classe qui contient le id, le nom et le prénom :

java -jar LazySloth.jar -both Exemple1 sid:pk snom:s100 sprenom:s100



Le code Java généré est :

public class Exemple1{

 String id;
 public void setId(String p){
  this.id = p;
 }
 public String getId(){
  return this.id;
 }

 String nom;
 public void setNom(String p){
  this.nom = p;
 }
 public String getNom(){
  return this.nom;
 }

 String prenom;
 public void setPrenom(String p){
  this.prenom = p;
 }
 public String getPrenom(){
  return this.prenom;
 }

}

Le code SQL généré est :

Create Table Exemple1(
 id Char(100) Primary Key,
 nom Char(100),
 prenom Char(100)
)

Comme un dernier exemple, cette commande teste les qutre types supprotés :

java -jar LazySloth.jar -both Exemple2 iid:pk snomprenom:s200 ddatenaissane nsolde


Le code Java généré est :

public class Exemple2{

 int id;
 public void setId(int p){
  this.id = p;
 }
 public int getId(){
  return this.id;
 }

 String nomprenom;
 public void setNomprenom(String p){
  this.nomprenom = p;
 }
 public String getNomprenom(){
  return this.nomprenom;
 }

 Date datenaissane;
 public void setDatenaissane(Date p){
  this.datenaissane = p;
 }
 public Date getDatenaissane(){
  return this.datenaissane;
 }

 double solde;
 public void setSolde(double p){
  this.solde = p;
 }
 public double getSolde(){
  return this.solde;
 }

}

Le code SQL généré est :


Create Table Exemple2(
 id Int Primary Key,
 nomprenom Char(200),
 datenaissane Date,
 solde Decimal(10, 2)
)

Le projet entier se résume en une seule classe Java qui peut être facilement modifiée pour ajouter de nouveaux types de données, de nouvelles contraintes ou pour exécuter d'autres commandes après la génération du code telles que la compilation des fichiers Java générés ou bien pour exécuter les scripts SQL créés.

Le projet se trouve à SourceForge, l'outil que j'ai toujours utilisé pour télécharger des projets OpenSource bien avant l'arrivée de GitHub. Vous pouvez le télécharger par ici.

mardi 28 novembre 2017

Apprendre Java : les frameworks et les langages JVM

Apprendre le langage Java ne veut pas dire apprendre sa syntaxe ou ses structures de base. Autrement, tout développeur C et C++ peut se voir comme un développeur Java. Apprendre Java veut dire un peu plus que la syntaxe.

Premièrement, il faut apprendre l'API Java. L'API Java fournie avec la JDK est très puissante. La majorité des applications J2SE reposent seulement sur l'API par défaut. Elle peut être considérée comme un facteur clé du succès du langage Java. Parmi les packages les plus utilisés :
  1. java.lang : le package importé par défaut et qui contient les classes essentielles pour écrire un programme Java (System, String, Class, Exception, Thread, etc..)
  2. javax.swing : (après AWT) pour les interface graphiques.
  3. javax.net : pour la programmation réseau.
  4. java.nio : (après io) pour les flux entrée/sortie.
  5. java.sql : pour interagir avec les Bases de Données relationnelles.
Ainsi, nous pouvons développer une application de gestion réparties, suivant l'approche Client/Serveur avec Client lourd, basée sur une Base de Données centralisée avec support de l'importation et l'exportation des données en utilisant la J2SE standard sans ajouter d'autres API sauf le driver du SGBDR utilisé (qui ne sera plus nécessaire s'il s'agit du Derby fourni avec la JDK).

Mais est-ce tout ? Non.

Deux autres éléments essentiels dans l'apprentissage de Java sont les framework et les langages JVM.

Premièrement, nous trouvons généralement les frameworks dans le cadre de développement des applications entreprises (n-tiers) sous J2EE. Ces framework ont trouvé de la popularité avec le retard remarquable qu'a fait la bibliothèque standard J2EE dans ce domaine. En effet, sans ce retard, les frameworks Spring et Struts n'auront pas gagné du terrain. Ainsi, à une époque donnée, apprendre la J2EE était synonyme de "apprendre une framework J2EE".

Aujourd'hui cette affirmation reste valide mais pas avec la même puissance. D'un côté, la J2EE devient de plus en plus à jour; elle arrive à cacher ses inconvénients et sa lourdeur qui limitent sa productivité (présentation Adam Bien). Elle arrive aussi à proposer ses propres frameworks disponibles par défaut; nous avons remarqué aussi la qualité améliorée de ces framework (Java Server Faces en ai un exemple). De l'autre côté, les différents frameworks continuent de progresser et gardent leur avance par rapport à la plate-forme J2EE part défaut. Les nouveaux besoins et les nouvelles approches favorisent ces frameworks et compliquent la tâche de la plate-forme par défaut.

Deuxièmement, nous devons reconnaître les langages JVM; des langages de programmation basés sur la machine virtuelle de Java. Ces langages sont, généralement, compatible directement avec Java et peuvent accéder à toutes les bibliothèques disponibles sans aucun effort supplémentaire. Ils compilent leur code vers Bytecode de Java et profite ainsi de sa portabilité.

Ces langages sont proposés pour plusieurs raisons :
  1. Simplifier et moderniser le langage : Java est un langage puissant mais lourd. Quelques langages sont proposés pour le simplifier et le moderniser. Groovy et Kotlin sont des excellents exemples.
  2. Pour répondre à un besoin spécifique : Java est un langage général qui permet de développer différents systèmes et pour différents domaines, néanmoins, avoir un langage spécialisé qui garde la puissance de Java reste une option intéressante. Tel est le cas avec des langages comme Scala (programmation formel), SARL (programmation basée Agents) et Processing (dessins et animations).
  3. Pour faciliter l'apprentissage de la programmation et du langage Java : Java est strict et nécessite un respect rigoureux des notions Objets; la chose qui n'est pas facile pour les débutants en programmation. Ainsi, quelques langage JVM sont conçu pour être facile et simple et pour cacher la lourdeur du Java. Javascool en est un excellent exemple.
 
 

La plus part de ces langages offrent leurs propres APIs. Ces APIs représentent un enrichissement remarquable à exploiter et à être pris en considération par les développeurs Java. Nous prenons, comme, exemple les chaînes de caractères sous Groovy. Ces chaînes de caractères sont implantées en utilisant la classe GString, une extension puissante de la classe String de l'API J2SE par défaut. En l'utilisant, nous pouvons, à titre d'exemple, bénéficier de :

1. La déclaration d'une chaîne de caractère sur plusieurs lignes (comme les commentaires sur plusieurs lignes) en utilisant le délimiteur """.


def maChaine = """Bonjour chèrs internautes,
Cela est un exemple sur les chaîne de caractères sur plusieurs lignes.
Merci Groovy."""

println maChaine


2. Il est possible d'effectuer des substitutions de variables en utilisant le $ associé à leurs noms dans la chaîne de caractères.


def monPrenom = "Tarek"

println "Bonjour ${monPrenom}."


Certain de ces langages ont pu prendre la place du Java. Kotlin, par exemple, est devenu le langage de développement des applications Android, malgré, qu'à la base, il n'était pas conçu pour cet objectif.

Ainsi, apprendre Java veut dire apprendre sa syntaxe, son API par défaut (J2SE et J2EE) et apprendre , selon vos besoins et votre spécialité, la framework ou le langage JVM le plus adéquat. A titre d'exemple, pour enseigner en présentiel et à distance, je me trouve orienté vers les langages Groovy, Javascool et Processing. Les frameworks, dans mon contexte professionnel, ne trouve pas assez de place à part des démonstrations très limitées pour les étudiants en Master (université de Jijel).

samedi 25 novembre 2017

Editeur des diagrammes Entité/Association en une soirée grace à Processing

La facilité de dessin et de gestion des évènement permet au développeur sous Processing de préparer rapidement des prototypes ou bien des outils dans un temps record. Cette capacité est très nécessaire lorsqu'il s'agit de prouver une idée ou bien pour préparer une démonstration rapide pour votre client.

Dans cet exemple, j'ai créé rapidement un éditeur des diagramme Entité/Association sous Processing dans environs 350 lignes de code. L'éditeur ne permet pas d'annuler, de déplacer de sélectionner les objets créés. Néanmoisn, il permet de :
  1. Créer des entités en faisant un clique gauche :
    1. L'entité est créée à l'endroit où le clique a eu lieu.
    2. L'éditeur vous demande le nom de l'entité qui ne doit pas être vide.
    3. Il vous demande, par la suite, une liste d'attributs, une à la fois. La création de la liste des attributs s'arrête lorsque la chaîne vide est entrée.
  2. Créer des associations en faisant un clique droit :
    1. L'association est créée à l'endroit où le clique a eu lieu.
    2. L'éditeur vous demande le nom de l'association qui ne doit pas être vide.
    3. Il vous demande, par la suite, une liste d'attributs, une à la fois. La création de la liste des attributs s'arrête lorsque la chaîne vide est entrée.
  3. Pour créer un lien, il faut dessiner une ligne d'un objet à un autre objet de différente nature (d'une entité vers une association ou bien d'une association vers une entité). Les autres liens seront refusés (l'unique vérification dans le système).
Au stade actuel, le système ne fait pas d'autres vérifications, c'est à dire, il est possible de créer deux entités avec le même nom, d'avoir deux attributs identiques et de mettre ce que vous voulez comme cardinalité. Mais, comme j'ai déjà mentionné, il s'agit d'une démo pour Processing plus qu'un éditeur.

Dans ce projet, vous pouvez voir comment différencier les bouttons de la souris en toute simplicit. Dans la méthode "mousePressed()", il est nécessaire de vérifier est ce qu'il s'agit d'un clique droit pour insérer une association ou bien d'un clique gaucheoù il faut véirifier est ce qu'il est appliqué à l'intérieur d'un objet ce qui veut dire qu'il s'agit d'un lien ou bien s'il est à l'extérieur de tout objet pour insérer une nouvelle entité.

void mousePressed(){
  if(mouseButton == LEFT){
    int entite = verifierEntites(mouseX, mouseY);
    if(entite != -1){
      creationLien = true;
      entiteSource = true;
      source = entite;
    }else{
      int association = verifierAssociations(mouseX, mouseY);
      if(association != -1){
        creationLien = true;
        entiteSource = false;
        source = association;
      }else{
        lireEntite(mouseX, mouseY);
      }
    }
  }else{
    lireAssociation(mouseX, mouseY);
  }
}

La vérification que le clique est à l'intérieur d'un objet se fait par rapport aux coordonnés et mesures de ce dernier. Ainsi dans la classe Objet, on trouve la méthode "estDedans()" :

  public boolean estDedans(int cx, int cy){
    return cx > x && cx < x + getLargeur() && cy > y && cy < y + getHauteur();
  }

La méthode qui est supposée faire toutes les vérifications concerant les noms des entitées, des associations et des attributs ne fait en réalité que lire ces valeurs sans aucune vérification; elle nécessite un effort supplémentaire :


void lireEntite(int mx, int my){
  String nom = JOptionPane.showInputDialog(null, "Donnez le nom de l'entité");
  if(nom != null && !nom.equals("")){
    Entite e = new Entite(mx, my);
    String propriete;
    int i = 0;
    do{
      propriete = JOptionPane.showInputDialog(null, "Donnez les propriétés (vide pour terminer)");
      if(propriete != null && !propriete.equals("")){
        e.addAttribut(propriete);
        i++;
      }
    }while(propriete != null && !propriete.equals("") && i < NOMBRE_MAX_ENTITES);
    e.setNom(nom);
    entites[nbrEntites] = e;
    nbrEntites++;
  }
}


Vous pouvez télécharger le code par ici.

Drag & Drop sous Processing en quelques lignes

L'interactivité sous Processing est très impressionnates. En quelque lignes, il est possible de récupérer et traiter les différents évènements prevenant de la souris ou bien du clavier. Cet exemple vise à donner un avant-goût de ces capacités.
Le Drag Drop consiste à lever un objet en cliquant dessus, le déplacer (le voir se déplacer) en gardant le clique et le déposer en relâchant le clique.

Sous Processing, nous pouvons exploiter les éléments suivants :
  •  Il est à tout moement possible de récupérer la position de la souris grâce à deux variables prédéfinies : museX, mouseY. Aucun code ou fonction ou Listener sont nécessaires.
  • Pour récupérer l'évènement du clique, il suffit d'implémenter la méthode "mousePressed()"; elle sera appelée si l'un des deux bouttons de la souris est enfoncé. mouseBoutton permet de connaître est ce qu'il s'agit d'un clique droit (RIGHT) u gauche (LEFT).
  • Pour récupérer l'évènement du relâche de la souris, il suffit d'implémenter la méthode "mouseReleased()".
Le seul élément que nous allons ajouter est une variable booléenne pour garder trace est ce que l'objet est entrain d'être déplacé ou pas. Le code suivant est le code de l'objet (nommé Activite, préparé dans un contexte précis) :

class Activite {
  
  int x, y;
  final int HEIGHT = 180;
  final int WIDTH = 180;
  
  public Activite(int x, int y){
    this.x = x;
    this.y = y;
  }
  
  void draw(){
    rect(x, y, HEIGHT, WIDTH);
  }
  
  void setX(int x){
    this.x= x;
  }
  
  void setY(int y){
    this.y = y;
  }
  
  int getX(){
    return x;
  }
  
  int getY(){
    return y;
  }
  
}

Ce code est presque un JavaBean, à l'exception de la méthode draw() qui déssine un rectangle.
Le code du Drag & Drop est :

Activite a;

int diffx, diffy;
boolean drawing = false;

void setup(){ 
  size(960, 480);
  a = new Activite(100, 100);
}

void draw(){
  background(240);
  
  if(drawing){
    a.setX(mouseX + diffx);
    a.setY(mouseY + diffy);
  }
  
  a.draw();
}

void mousePressed(){
  diffx = a.getX() - mouseX;
  diffy = a.getY() - mouseY;
  drawing = true;
}

void mouseReleased(){
  drawing = false;
}

Les deux variables diffx et diffy c'est pour garder la distance entre la position de la souris et la position de l'objet au départ de l'action.

Une version abrégée de ce code peut montrer qu'il est possible d'implémenter le tout avec toutes les données et les fonctions en moins de 30 lignes en gardant notre code claire at aéré:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
int x, y, h, w;
int diffx, diffy;
boolean drawing = false;

void setup(){ 
  size(960, 480);
  x = 100; y = 100;
  h = 100; w = 250;
}

void draw(){
  background(240);
  if(drawing){
    x = mouseX + diffx;
    y = mouseY + diffy;
  }  
  rect(x, y, w, h);
}

void mousePressed(){
  diffx = x - mouseX;
  diffy = y - mouseY;
  drawing = true;
}

void mouseReleased(){
  drawing = false;
}

Chute libre dans le vide sous Processing

Simuler une phénomène naturel en utilisantl'animation est un moyen excellent pour l'enseigner et pour l'expliquer. Cette approche permet, aussi, de modifier les différents paramètres et voir les différents scénarios possibles avec un coût (pratiquement) nul.
Dans cet exemple, nous allons simuler une chute libre dans le vide. Pour rendre la simualtion un peu plus réel, nous allons ajouter un effet de rebond par définir un facteur de préservation de l'énergie au moement de l'impact au sol.
L'objet en question est une boule. Elle sera définie comme un objet séparé pour donner la possibilité de comparer plsuieurs chutes avec des paramètres différents.
Le problème peut être modélisé suivant deux approches :
  • L'utilisation des équations en fontion du temps "t", la position et la vitesse de l'objet seront calculées en fontion de l'instant "t" de l'animation.
  • En utilisant des suites pour la vitesse te la position. Les paramètres de l'instant "t" seront obtenus en fontion des paramètres de l'instant "t - 1".
Dans cet exemple, nousa allons suivre cette deuxième approche. Le passage d'un instant à l'instant suivant est implémenté sous la forme d'une fonction que nous appelerons chaque intervalle du temps (un autre paramètre que nous pouvons modifier à notre guise).

 


Le code principal est très simple. Il initialise l'environnement et déclare une boule. Chaque fois, il dessine la boule avec sa position, sa vitesse et son énergie.


Boule b;

void setup(){
  size(600, 400);
  b = new Boule(100, 0, 50, 10, 0.9f);
}

void draw(){
  background(255);
  b.draw();
  if(frameCount % 6 == 0)
    b.instantSuivant();
  fill(0);
  text("" + b.getVitesse(), 10, 30);
  text("" + b.getEnergie(), 10, 50);
  text("" + b.getY(), 10, 70);
};

Le code  de l'objet Boule permet de garder les différentes information de la boule, de simuler la chute et de déssiner la boule :


class Boule {
  
  public final static float G = 1f;
  
  float preservation;
  int x, y, diametre, vitesse, masse, energie;
  
  public Boule(int x, int y, int diametre, int masse, float preservation){
    this.x = x;
    this.y = y;
    this.diametre = diametre;
    this.masse = masse;
    this.preservation = preservation;
  }
  
  public void instantSuivant(){
    y += vitesse;
    energie = masse * vitesse * vitesse / 2;
    if(y >= height - diametre / 2){
      vitesse = (int)(-1 * preservation * Math.sqrt(2 * energie / masse));
    }else{
      vitesse += G;
    }
  }
  
  public void draw(){
    fill(255);
    stroke(0);
    ellipse(x, y, diametre, diametre);
  }
  
  public int getVitesse(){
    return vitesse;
  }
  
  public int getEnergie(){
    return energie;
  }
  
  public int getY(){
    return y;
  }
  
  public int getX(){
    return x;
  }
    
  
}

La fonction qui nous intéresse le plus est la fonction "instantSuivant()". Elle montre le changement appliqué sur la vitesse :


  public void instantSuivant(){
    y += vitesse;
    energie = masse * vitesse * vitesse / 2;
    if(y >= height - diametre / 2){
      vitesse = (int)(-1 * preservation * Math.sqrt(2 * energie / masse));
    }else{
      vitesse += G;
    }
  }

  • Si l'objet est en chute, la vitesse est influencée par la gravité seulement.
  • Si la boule touche le sol, la gravité n'est plus appliquée mais c'est le rebond qui repousse la boule vers le haut.
 
L'état final de l'animation est la boule immobile au fon d de l'écran (le sol).
Nous pouvons facilement ajouter une autre boule pour comparer les deux chutes :


Boule b1, b2;

void setup(){
  size(600, 400);
  b1 = new Boule(100, 0, 50, 10, 0.9f);
  b2 = new Boule(200, 0, 80, 10, 0.5f);
}

void draw(){
  background(255);
  b1.draw();
  b2.draw();
  if(frameCount % 6 == 0){
    b1.instantSuivant();
    b2.instantSuivant();
  }
  fill(0);
  text("b1", 10, 10);
  text("" + b1.getVitesse(), 10, 30);
  text("" + b1.getEnergie(), 10, 50);
  text("" + b1.getY(), 10, 70);
  text("b2", 10, 90);
  text("" + b2.getVitesse(), 10, 110);
  text("" + b2.getEnergie(), 10, 130);
  text("" + b2.getY(), 10, 150);
};