Homework

Headlines
Numbers… (and their representation)

N°INSEE

Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript dans une classe N_INSEE un système de saisie contrôlée d'un N°INSEE (ou N°SS) selon la formule suivante : clef = 97 - (N°INSEE % 97). On rappelle qu'un N°INSEE est défini sur 13 chiffres (e.g., 1630125388055, clef = 29) et que sa clef est saisie simultanément pour contrôle.

En C++, il est nécessaire de vérifier qu'un N°INSEE tient sur le format long et dans le cas contraire le remplacer par le format long long, e.g., long long n_insee_de_Franck_Barbier = 1630125388055LL; (ne pas oublier le suffixe LL derrière la constante). Si l’on passe par des chaînes de caractères (i.e., std::string), il faut utiliser la fonction C de conversion std::atoll (#include <cstdlib>) pour convertir des chaînes de caractères en variables de type long long.

Contrôler qu'un N°INSEE saisi est « bien formé » (i.e., 13 chiffres exactement, 1er chiffre égal à 1 ou 2, etc.) en définissant et utilisant une expression régulière. Il est possible de tester en direct son expression régulière ici… Tutoriel Java :

En JavaScript/TypeScript, pour signifier le résultat à l'utilisateur, utiliser la librairie SweetAlert2. A ce titre, faire apparaître un message différencié selon l'issue du calcul de clef (i.e., OK ou Non OK). Organiser le code en deux fichiers source différents, l'un (N_INSEE.js) faisant le calcul et l'autre (Main.js) l'interaction homme-machine. Pour le premier fichier, utiliser export et le second utiliser import.
Note : il semble que la réutilisation de SweetAlert2 via import ne fonctionne pas en JavaScript/TypeScript malgré ce qui est annoncé sur le site Web.

Avec Angular, partir de l'implémentation TypeScript précédente pour obtenir le visuel qui suit.

Faire de même avec React en partant de l'implémentation JavaScript.

Application(s)
Predefined versus user-defined types

Before yesterday, yesterday…

En s'inspirant d'un programme C++ déterminant en fonction du temps machine si une date donnée est « Avant hier », « Hier »…, implanter en Java et/ou Python et/ou JavaScript/TypeScript un programme équivalent.

Pour Java, il y a lieu de mettre en œuvre l'API Date-Time qui a complètement été revue en Java 8 (ici).

// Before_yesterday_.h
#ifndef _Before_yesterday_H
#define _Before_yesterday_H

#include <string>

class Before_yesterday_ {
public:
    static const std::string Avant_hier;
    static const std::string Hier;
    static const std::string Aujourd_hui;
    static const std::string Demain;
    static const std::string Apres_demain;
    static const std::string Je_n_en_sais_rien;

    Before_yesterday_(int, int, int, std::string&);
};

#endif

// Main.cpp
#include <cassert>
#include <ctime>

#include <iostream>
#include <string>

#include "Before_yesterday_.h"

const std::string Before_yesterday_::Avant_hier = "Avant hier";
const std::string Before_yesterday_::Hier = "Hier";
const std::string Before_yesterday_::Aujourd_hui = "Aujourd'hui";
const std::string Before_yesterday_::Demain = "Demain";
const std::string Before_yesterday_::Apres_demain = "Après demain";
const std::string Before_yesterday_::Je_n_en_sais_rien = "Je n'en sais rien";

Before_yesterday_::Before_yesterday_(int jour, int mois, int annee, std::string& resultat) {
    assert(jour > 0 && mois > 0 && annee > 0);
    assert(jour <= 31 && mois <= 12);

    std::time_t maintenant = std::time(&maintenant);
    //    std::cout << std::asctime(std::localtime(&maintenant)) << std::endl;

    std::tm *maintenant_comme_structure_de_donnes = std::gmtime(&maintenant);
    // 'auto' permet de déterminer automatiquement le type de 'jour_systeme' en fonction du type (ici 'int') de la donnée affectée : 
    auto jour_systeme = maintenant_comme_structure_de_donnes->tm_mday;
    auto mois_systeme = maintenant_comme_structure_de_donnes->tm_mon + 1; // Attention : 'tm_mon' retourne le mois système moins '1' !
    auto annee_systeme = maintenant_comme_structure_de_donnes->tm_year + 1900; // Attention : 'tm_year' retourne l'année système moins '1900' !

    resultat = Je_n_en_sais_rien;
    if (annee == annee_systeme) {
        if (mois == mois_systeme) {
            if (jour == jour_systeme - 2) resultat = Avant_hier;
            if (jour == jour_systeme - 1) resultat = Hier;
            if (jour == jour_systeme) resultat = Aujourd_hui;
            if (jour == jour_systeme + 1) resultat = Demain;
            if (jour == jour_systeme + 2) resultat = Apres_demain;
        }
    }
}

int main(int argc, char** argv) {
    std::string resultat;
    Before_yesterday_ Before_yesterday_(9, 5, 2019, resultat);
    std::cout << resultat << std::endl;

    return 0;
}
Application(s)

Leap year

Implanter en C++ et/ou Java et/ou Python dans une classe Leap_year, deux fonctions booléennes établissant si, oui ou non, une année est bissextile (leap year en anglais). La première fonction prend en paramètre l'année sous forme entière alors que la seconde la prend sous forme d'un type gérant les dates.

Pour C++, ce type est time_t (#include <ctime>) ou mieux, on utilise l'API <chrono> complètement relookée en C++ 17.

Pour Java, ce type peut être java.util.Calendar ou mieux, on utilise l'API java.time complètement relookée en Java 8 (tutoriel : ici).

Les deux exemples qui suivent donnent une méthode de récupération de l'année du temps machine en C++ et Java.

std::time_t now = std::time(&now); // '#include <ctime>'
// Display for control:
std::cout << std::asctime(std::localtime(&now)) << std::endl; // '#include <iostream>'
std::tm *now_as_data_structure = std::gmtime(&now);
int year = now_as_data_structure->tm_year; // Caution: 'tm_year' returns the current year minus '1900'!
java.util.Calendar now = java.util.Calendar.getInstance();
int year = now.get(java.util.Calendar.YEAR);

En TypeScript, implanter une fonction Leap_year prenant la date dans le type primitif string puis transformer la date dans le type Date en vue d'établir si la date est bissextile (indication : Date.parse).

Application(s)

Lotto!

Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript dans une classe Tirage_loto un calcul permettant de remplir automatiquement une grille de loto simple avec 48 valeurs différentes à choisir entre 1 et 49 inclus. On a en fait 8 jeux consistant à choisir à chaque fois 6 chiffres mais on n'utilise pas les mêmes chiffres entre chaque jeu.

Pour gérer des suites de nombres aléatoires, on utilise opportunément :

Note : il faut veiller à optimiser l'algorithme, en l'occurrence il faut tirer un nombre dans l'ensemble des nombres non encore tirés plutôt que tirer dans l'absolu un nombre entre 1 et 49 (inclus) et re-tirer (récursivement) si ce nombre a déjà été tiré…

Application(s)

Color

Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript une classe RGB_color sur le modèle Java qui suit. Une couleur RGB est représentée sur 32 bits : 8 bits les plus à gauche pour l'opacité puis 8 bits pour la nuance de rouge, etc.

public class RGB_color { // RGB: 8 left-most bits: alpha, then next 8 bits: red, green, blue...
    public enum Red_shade { // Look at red color named shades in CSS and HTML on the Web...
        crimson, darkred, tomato // Etc.
    };
    public RGB_color(String css_html_hexadecimal) { // Use a regular expression to check 'css_html_hexadecimal' format,
        // e.g., "#FFFF0000" for "fully opaque red"...
        // Construct '_representation' from 'css_html_hexadecimal'...
    }
    private java.util.BitSet _representation = new java.util.BitSet(Byte.SIZE * 4);
    public float alpha() {
        // '0.F' if totally transparent, '1.F' if totally opaque, between '0.F' and '1.F' otherwise
        return ...;
    }
    public boolean is_color(Red_shade red_shade) {
        // 'true' if 'red_shade' is color implemented as bit set in '_representation'
        return ...;
    }
    public String css_html_hexadecimal() {
        String css_html_hexadecimal;
        // Construct 'css_html_hexadecimal' from '_representation', for example, "fully opaque red":
        return "#FFFF0000";
    }
}

Account

Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript une classe Account sur la base du type abstrait de données Account.

TYPES FUNCTIONS AXIOMS PRE-CONDITIONS

Temperature

Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript le concept de température sachant qu'une température ne peut pas descendre en dessous du zéro absolu. Cette propriété peut être formalisée via une fonction accessor constante sur le type abstrait de données Temperature comme suit :

La fonction Min est basée sur l'axiome suivant :

Par ailleurs, il existe trois unités de mesure des températures qui sont les °C, les °F et les °K. Ces trois unités sont matérialisées par les trois fonctions accessor suivantes :

Les deux axiomes suivants s'appliquent :

Prévoir des fonctions d'incrémentation et de décrémentation avec un pas « fin » (10-3 ou moins) matérialisé par une variable d'instance _step.

Pour Java, créer une classe Temperature_UI (utiliser Swing ou mieux JavaFX*) contrôlant la température de façon à ne pas descendre en dessous de 40°Fahrenheit et ne pas monter au-dessus de 90°Fahrenheit (afficher ces valeurs de manière fixe dans l'interface homme-machine). Pour changer la valeur de la température, prévoir un slider. Pour visualiser la valeur courante de la température, prévoir au plus simple du texte ou une autre métaphore visuelle (e.g., « barres »). En option, prévoir une checkbox qui régit l'unité d'expression de la température entre °C et °F uniquement.

*L'outil JavaFX Scene Builder peut être intégré dans Apache NetBeans pour dessiner l'interface homme-machine.

Pour JavaScript/TypeScript, appliquer les mêmes règles que pour Java et créer l'interface homme-machine dans une page Web avec HTML et CSS.

Application(s)
Array, dictionary…

Face detection

Ce travail concerne les tableaux JavaScript (type Array : doc. ici…) qui jouent un rôle extrêmement important. Un logiciel de détection de caractéristiques (la face en bleu, la bouche en vert et les yeux en rouge) donne des résultats pléthoriques nécessitant un post-processing.

Le post-processing consiste à appliquer des heuristiques simples comme par exemple le fait que « les yeux se trouvent au-dessus de la bouche » ou encore « la bouche et les yeux sont totalement inclus dans la face » (voir toutefois Macron pour qui cette heuristique est inadaptée). Dans le logiciel de détection, this._eyes est une promesse JavaScript  qui par la fonction then permet d'accéder à un tableau eyes ; eyes.length est alors le nombre d'yeux trouvés. Au-delà, eyes[0].x et eyes[0].y représentent le coin supérieur gauche du rectangle bornant le premier œil alors que eyes[0].width et eyes[0].height donnent la largeur et hauteur du rectangle. L'idée du travail à réaliser est d'utiliser les primitives sur les tableaux de manière à améliorer la qualité de détection.

L'exemple d'application d'heuristique qui suit est : « on ne garde que la bouche la plus basse ».

this._mouth.then(function (mouth) {
    if (mouth !== null && mouth.length > 1)
        mouth.sort(function (mouth1, mouth2) {
            return mouth2.y - mouth1.y;
        }).splice(1, mouth.length - 1);
});

Les 2 yeux tels que le décalage sur l'axe y soit le plus faible possible.

this._eyes.then(function (eyes) {
    eyes.sort(function (eye1, eye2) { // Les 2 yeux vérifiant l'heuristique sont placés en début de 'eyes'
        return this.reduce(function (min, eye) {
            return this === eye ? Math.min(min, this.y) : Math.min(min, Math.abs(this.y - eye.y));
        }.bind(eye1), eye1.y) - this.reduce(function (min, eye) {
            return this === eye ? Math.min(min, this.y) : Math.min(min, Math.abs(this.y - eye.y));
        }.bind(eye2), eye2.y);
    }.bind(eyes)).splice(2, eyes.length - 2); // Les yeux sont triés, on ne garde que les 2 premiers...             
});
Application(s)

Horner

Implanter en C++ et/ou Java et/ou Python et/ou TypeScript la méthode de Horner qui est un mécanisme efficace d'évaluation d'un polynôme en un point x. Elle se base sur la factorisation de x qui est multiplié au résultat de l'itération antérieure. Utiliser éventuellement la librairie SweetAlert2 en TypeScript pour saisir le polynôme.

La difficulté réside dans le choix de la structure de données pour stocker le polynôme (idéalement un dictionnaire) sachant qu'il est utile que le polynôme soit rangé dans l'ordre croissant des puissances de x.

Application(s)

Lips

Le but du travail est de manipuler les tableaux en JavaScript (type Array : doc. ici). L'application 3D qui suit montre une géométrie de lèvres « brute ». Une géométrie est fondée sur un tableau de sommets (vertices en anglais) et un tableau de faces. Si g est une géométrie alors g.vertices et g.faces sont deux tableaux de type Array. Une face est composée de trois sommets exactement. Si f est une face alors f.a, f.b et f.c sont des index dans le tableau de sommets. A titre d'illustration, g.vertices[f.a] est un des trois sommets de la face f.

Before processing

L'application 3D qui suit montre la géométrie de lèvres reconstruite. En fait, les tableaux vertices et faces ont été ré-organisés (re-triés spécialement) de manière à isoler cinq zones distinctes. A titre d'illustration, en jouant sur le paramètre Color, on colorie en blanc la zone la plus extérieure des lèvres.

After processing

En résumé, à partir de l'application 3D basée sur la géométrie de lèvres « brute », il faut aboutir à la géométrie de lèvres reconstruite.

Application(s)
Genericity

Palindrome

Soit un programme C++ permettant de détecter si une phrase est un palindrome c'est-à-dire la possibilité de la lire de la droite vers la gauche en ignorant les caractères non alphabétiques.
On doit en particulier s'intéresser à la notion de n-uplet (tuple en anglais) incarnée par la classe générique template<class T1,class T2> struct pair (2-uplet uniquement) et plus généralement la classe générique template<class... Types> class tuple en C++.

Traduire ce programme en Java et/ou Python et/ou JavaScript/TypeScript en gérant les accents français ainsi que le « ç » voire d'autres caractères « problématiques ».

En JavaScript/TypeScript, utiliser la balise HTML input en conjonction avec les événements 'input' (un caractère saisi) et 'change' (tous les caractères saisis). Tenter de détecter au plus tôt avec l'événement input, le milieu du palindrome où s'effectue le basculement : « élu par cet<basculement>te crapule ».

<input placeholder="Enter palindrome here..." name="palindrome"/>
window.document.querySelector('input').addEventListener('input', () => {
    …
});

C++

// Palindrome.h
#ifndef  _Palindrome
#define  _Palindrome

#include <string>
#include <utility> // 'std::pair'

class Palindrome : public std::string {
private:
    // 'constexpr' works with 'static' only...
    // 'constexpr' avoids allocation in compilation unit, i.e., '.cpp' file
    // 'constexpr' allows immediate initialization:
    constexpr static /* const */ std::pair<char, char> _Intervals[] = { std::pair<char, char>('a', 'z'), std::pair<char, char>('A', 'Z') };
public: // Something less than '3' -> compilation "error: excess elements in struct initializer"
    constexpr static /* const */ std::array<char, 3> Special_characters{ ' ', '\n', '\t' };
public:
    Palindrome(const std::string&);
    virtual bool isPalindrome() const;
    const char* toString() const;
};

#endif

// Palindrome.cpp
#include <cctype> // 'std::tolower'
#include <iterator> // C++17: 'std::size'
#include <string> // 'std::string'
#include <utility> // 'std::pair'

#include "Palindrome.h"

Palindrome::Palindrome(const std::string& string) {
    for (char c : string) { // For each character in the source string
        for (int j = 0; j < std::size(_Intervalles); ++j) { // C++17
            if (c >= _Intervals[j].first && c <= _Intervals[j].second) { // The character belongs to the authorized intervals
                this->push_back(c); // Character is valid and thus added to the palindrome
                break; // Quit the 'for' loop on 'j'
            }
        }
    }
}

bool Palindrome::isPalindrome() const {
    for (int i = 0; i < this->length() / 2; ++i) { // For each character in the palindrome (up to half of the palindrome's length)
        // 'std::tolower': 'A' -> 'a'
        if (std::tolower(this->operator[](i)) != std::tolower(this->operator[](this->length() - 1 - i)))
            return false;
    }
    return true;
}

const char* Palindrome::toString() const {
    return this->data(); // Content of a string as 'const char*' for compatibility with the C programming language...
}

// Main.cpp
#include <iostream>

#include "Palindrome.h"

int main(int argc, char** argv) {
    Palindrome p1("Elu par cette crapule"); // French
    Palindrome p2("Esope reste ici et se repose"); // French
    Palindrome p3("Was it a car or a cat I saw?"); // English
    Palindrome p4("This is not a palindrome"); // English

    std::cout << p1.toString() << ": " << (p1.isPalindrome() ? "true" : "false") << '\n'; // 'true'
    std::cout << p2.toString() << ": " << (p2.isPalindrome() ? "true" : "false") << '\n'; // 'true'
    std::cout << p3.toString() << ": " << (p3.isPalindrome() ? "true" : "false") << '\n'; // 'true'
    std::cout << p4.toString() << ": " << (p4.isPalindrome() ? "true" : "false") << '\n'; // 'false'

    return 0;
}
Application(s)
Inheritance and polymorphism

Currency

Un programmeur C++ a écrit une classe Currency (ici) ainsi qu'un programme simple manipulant cette classe. La hiérarchie d'héritage proposée s'appuie sur l'héritage multiple de classes en C++. Revoir en Java et/ou Python et/ou JavaScript/TypeScript cette classe Currency ainsi que ses descendantes. Construire en suivant les classes Moroccan_Dirham et Dollar. Dans une autre branche de la hiérarchie, construire la classe Bitcoin comme sous-classe d'une classe Crypto_currency.

Un programmeur Java a écrit une classe Currency (ici) ainsi qu'un programme simple manipulant cette classe. La hiérarchie d'héritage proposée s'appuie sur l'héritage de classes et l'implémentation d'interfaces en Java. Revoir en C++ et/ou Python et/ou JavaScript/TypeScript cette classe Currency ainsi que ses descendantes. Construire en suivant les classes Moroccan_Dirham et Dollar. Dans une autre branche de la hiérarchie, construire la classe Bitcoin comme sous-classe d'une classe Crypto_currency.

Application(s)

Telecom

Alcatel, ex. grand équipementier télécom français a développé en C++ une classe permettant de manipuler des vecteurs de bits de taille a priori infinie. L'idée est de pouvoir agir sur chaque bit dans le flux, faire des opérations logiques, réserver des portions du flux en leur donnant des significations particulières comme par exemple des checksum lors de transmissions télécom. Tout cela est basé sur un encombrement mémoire minimal et une vitesse d'exécution des opérations sur le flux la meilleure possible vu la nature « système » des traitements envisagés. Les applications reposant sur ce genre de concept informatique sont nombreuses et variées comme la codification et la transmission de messages, la compression, la gestion de flux multimédia, etc.

Dans le code C++ figure l'exemple d'une classe Message pour la transmission de messages de 16 bits au sein d'une infrastructure sous-marine de réseaux à fibre optique. Cet équipementier s'est demandé l'intérêt d'aller plus en avant dans l'extension et donc la maintenance de cette classe Message. En effet, tant C++ (std::bitset) que Java (java.util.BitSet) proposent des composants logiciels capables de « motoriser » la classe Message.

Revoir en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript la classe C++ Message.

public class Bit {
    private final boolean _implementation;

    public Bit(char c) {
        _implementation = c == '0' ? false : true;
    }
    // Other constructors and methods here...
}

public class Message /* extends ? */ {
    ...
    public Bit start_bit() { return new Bit('0'); } // Bit 1: set to 0
    public java.util.BitSet address() { ... } // Bits 2->11
    public Bit direction() { ... } // Bit 12
    public java.util.BitSet command_code() { ... } // Bits 13->15
    public Bit parity() { ... } // Bit 16
}
Application(s)

Central Intelligence Agency

Un programme Java faisant hériter une classe Confidential_note d'une classe Note montre l'impossibilité de redéfinir des méthodes déclarées private en Java. Il en résulte qu'une méthode déclarée private en Java est implicitement final, i.e., non rédéfinissable du point de vue de l'héritage.

Traduire ce programme en C++ et/ou Python et/ou JavaScript/TypeScript en vérifiant si ces langages autorisent de poser de telles contraintes sur l'héritage ?

public class Note { // Fichier 'Note.java'

    private final static char _Caractere_de_fin = '\n';
    private final static String _Entete_par_defaut = "Pour information : ";
    private final static int _Nombre_d_espaces_par_defaut = 1;
    private final String[] _source;
    protected String _texte;

    public Note(String[] source, String entete) {
        _source = source;
        initialization(entete);
    }

    protected void initialization(String entete) {
        if (entete != null) {
            _texte = entete;
        } else {
            _texte = _Entete_par_defaut;
        }
    }

    public String construire() {
        for (String s : _source) {
            _texte += s;
            for (int i = 0; i < _Nombre_d_espaces_par_defaut; i++) {
                _texte += ' ';
            }
        }
        _texte += _Caractere_de_fin;
        return _texte;
    }
}
…
public class Confidential_note extends Note { // Fichier 'Confidential_note.java'

    private final static String _Entete_par_defaut = "Pour information (confidentiel) : ";

    public Confidential_note(String[] source, String entete) {
        super(source, entete);
    }

    protected void initialization(String entete) {
        // On est obligé de redéfinir la fonction 'initialization' car '_Entete_par_defaut' est différent...
        if (entete != null) {
            super.initialization(entete);
        } else {
            _texte = _Entete_par_defaut;
        }
    }
}
Application(s)

Vegetables

Un légume est la partie comestible d’une plante potagère. Parfois, on en consomme les fruits, d’autres fois, les feuilles, mais on peut aussi en consommer les tiges, les graines ou les racines… Selon la partie de la plante qui est consommée, on distingue plusieurs catégories de légumes :

Sur la base de cette classification des légumes, donner le code sous forme de graphe d’héritage en C++ et/ou Java et/ou JavaScript/TypeScript et/ou Python à partir de la classe suivante :

class Vegetable {
public:
    virtual Vegetable* seed() const = 0; // Retourne un clone du légume en question, i.e., un clone de 'this'...
};
abstract public class Vegetable {
    abstract public Vegetable seed(); // Retourne un clone du légume en question, i.e., un clone de 'this'...
}
class Vegetable { // JavaScript!
    // On simule avec 'return undefined;' le fait que 'seed' est une méthode abstraite, i.e.,
    // on aurait utilisé le mot-clef 'abstract' en Java mais il n'existe pas en JavaScript alors qu'il existe en TypeScript :
    seed() { return undefined; } // Retourne un clone du légume en question, i.e., un clone de 'this'...
}

C++ : donner ensuite un exemple de polymorphisme basé sur les références C++ et découlant du graphe d’héritage construit.

C++ : on fait l'hypothèse qu'il existe une classe abstraite pré-existante Fruit ; que devient le graphe d'héritage ?

Java/TypeScript : on fait l'hypothèse qu'il existe une interface ou une classe abstraite pré-existante Fruit ; que devient le graphe d'héritage ?

Java/TypeScript : remplacer (dans une version alternative) la classe Vegetable par une interface et donner le lien entre l'interface Vegetable et le type « légumes-feuilles ». Créer en suivant une classe générique Soup_recipe possédant un Set de Vegetable.

Remarque générale : il est inutile d’implanter tous les légumes cités avant ; une classe suffit (Celeri, Laitue, Poireau…) pour illustrer chacune des sous-branches de la classification.

Application(s)
Complexity

Quick sort

Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript le tri lent et le tri rapide (quick sort en anglais)

En C++, faire des mesures de temps calcul grâce aux types time_t et tm (#include <ctime>) de la bibliothèque standard ou timeb (#include <sys/timeb.h>) de la bibliothèque « système » (localisation avec more < /usr/include/sys/timeb.h sous UNIX).

Faire de même en Java sans mesure de temps calcul puis, dans un second temps, réutiliser la classe Java java.util.Collections et ses méthodes sort.

Faire de même en Python sans mesure de temps calcul puis, dans un second temps, réutiliser la classe Python list et sa fonction sort.

Faire de même en JavaScript/TypeScript sans mesure de temps calcul puis, dans un second temps, réutiliser la classe JavaScript Array et sa fonction sort.

Pour remplir les tableaux à trier en gagnant du temps, on peut opportunément utiliser :

Application(s)

Fibonacci

Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript la suite de Fibonacci sur la base de trois méthodes de calcul : méthode récursive, méthode itérative ou formule de Binet.

Faire des mesures de temps calcul (cf. Quick sort) et expliquer les performances inhérentes aux trois méthodes lorsque les nombres en entrée deviennent « grands ».

Application(s)

Euclid

Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript l'algorithme d'Euclide.

Introduire une variable « artificielle » mesurant le coût du calcul récursif (i.e., incrémenter le coût de 1 à chaque appel récursif). Vérifier empiriquement que ce coût est proche de log(b) si on calcule euclid(a,b).

Application(s)
Security

RSA algorithm

L'algorithme RSA est un algorithme de cryptage basé sur des mathématiques (fichier PDF ici…). Faire une implémentation en Java de cet algorithme en tirant parti de la classe java.math.BigInteger qui offre en standard les calculs mathématiques exposés dans le fichier PDF.

Application(s)
Web

Currency++

L'étude de cas Currency utilise « en dur » dans le code les taux de conversion à l'Euro et/ou au Dollar. Etendre cette étude de cas en allant chercher ces taux de conversion de façon actualisée sur un site Web idoine, par exemple, Open Exchange Rates ou Fixer.

En JavaScript/TypeScript, utiliser l'interface XMLHttpRequest (ici…) ou mieux l'API fetch (ici…) pour interroger un site Web. Prévoir une interface homme-machine HTML-CSS permettant de faire les conversions avec, notamment, le Dirham marocain et le Bitcoin.

En Java, interroger un site Web et traiter des données JSON sont des sujets expliqués ici. Utiliser l'API native de Java ou, par exemple, la bibliothèque OkHttp. Prévoir une interface homme-machine permettant de faire les conversions en choisissant l'une ou l'autre des modalités suivantes :

  1. Utiliser JavaFX,
  2. Ou communiquer les données Java à JavaScript/TypeScript grâce à la technologie WebSockets (des archétypes de collaboration sont expliqués et disponibles ici…). Prévoir une interface homme-machine HTML-CSS permettant de faire les conversions avec, notamment, le Dirham marocain et le Bitcoin.

Note : le passage par un proxy en Java peut demander une configuration idoine (voir ici…), par exemple :

System.setProperty("http.proxyHost", "cache.franckbarbier.com");
System.setProperty("http.proxyPort", "1963");
Application(s)

Image processing

Le but du travail est de s'intéresser aux objets JavaScript de type HTMLCanvasElement (spec. ici). On peut aisément créer dynamiquement un canvas.

let canvas = window.document.createElement('canvas');
canvas.id = "My canvas";
canvas.width = 1200;
canvas.height = 800;
canvas.style.zIndex = 10;
canvas.style.position = "absolute";
canvas.style.border = "1px solid";
window.document.body.appendChild(canvas);

Un canvas offre des fonctions de dessin et/ou il est rempli via une image. Dans le second cas, il est alors intéressant de pouvoir faire des traitements d'image (illustration ici) via l'accès aux pixels du canvas. Toutefois, ces traitements peuvent être couteux en temps machine d'où la nécessité de travailler directement avec des background buffers qui sont formatés spécialement pour des accélérations GPU (illustration ici).

Voici un exemple de traitement d'image de manière à reconstruire cette image dans un monde 3D.

En s'aidant de la bibliothèque logicielle dat.GUI, le travail consiste à construire une page Web dans laquelle on charge une image puis on opère des changements comme ceux proposés ici. On rappelle qu'il faut manipuler les pixels avec les background buffers.

Application(s)

Drag & Drop

Le but du travail est de s'intéresser aux événements JavaScript clavier, souris ainsi qu'aux événements Drag & Drop. Considérant l'application JavaScript en fonctionnement ci-dessous, on souhaite faire évoluer son fonctionnement comme suit :

  1. On veut pouvoir à tout moment annuler le compte à rebours en cours avec la souris puis on saisit une donnée définissant une nouvelle valeur de compte à rebours ; on redémarre le compte à rebours.
  2. Avec la souris toujours, on veut pouvoir effectuer une pause du compte à rebours en cours ; on le reprend à la demande.
  3. On veut pouvoir à tout moment changer l'image (la texture en fait) de l'objet 3D injecté via un Drag & Drop. Attention, le Drag & Drop est ici un glisser-lâcher d'un fichier image provenant du système d'exploitation. Par défaut, un browser affiche cette image. Ce comportement par défaut doit donc être redéfini.

Mise à jour de la texture :

new THREE.TextureLoader().load(/* URL du fichier récupéré via 'FileReader' */, function(texture) {
    const bus = this._scene.getObjectByName(this._image_URL);
    bus.material.map = texture;
    bus.material.needsUpdate = true;
}.bind(this));
Application(s)

Jeu de découverte de personnage

Le but du jeu est de trouver le nom d'un personnage dans un temps limité. S'affichent le temps restant en millisecondes ainsi qu'une zone de saisie permettant de répondre.

Les données du jeu peuvent être organisées comme suit :

export default class Game {
    static Data = new Array(
            {
                Answer: /O[b]+a[m]+a/i, // ObbamMa
                URLs: [
                    "./img/Obama-1.jpg",
                    "./img/Obama-2.jpg"],
                Time: 10000
            },
            {
                Answer: /Tr[ou]+mpe?/i, // 'Trompe' accepté !
                URLs: [
                    "./img/Trump-1.jpg",
                    "./img/Trump-2.jpg"],
                Time: 10000
            }
    // Etc.        
    );
…
}

L'idée est de transformer la réponse du joueur en promesse à partir de l'événement 'change' de la balise input :

const reponse_complete = new Promise(resultat => {
    window.document.getElementById("reponse").addEventListener('change', (event) => {
        // L'événement 'change' est produit par JavaScript lorsque l'utilisateur a tapé "Return"...
        if (Game.Data[personnage].Answer.test(event.target.value)) resultat("gagné");
        else resultat("perdu");
    });
});

Il faut faire de même avec le timer ainsi que l'événement 'input' de la même balise input. Au final, est affiché « gagné » ou « perdu » sur l'image selon que la réponse est correcte ou que le timer « claque ».

Application(s)

Prise de photographie

Le but est de convertir en TypeScript un programme JavaScript Node.js basé sur les 2 modules qui suivent :

const file_system = require('fs'); // https://nodejs.org/api/fs.html
const https = require('https'); // https://nodejs.org/api/https.html

module.exports.save_image_from_URL = function () {
    https.get('https://i5.walmartimages.ca/images/Large/912/760/6000197912760.jpg', response => {
        response.pipe(file_system.createWriteStream('./Nutella.jpg'));
    });
};
const Save_image_from_URL = require('./Save_image_from_URL');

console.log(typeof Save_image_from_URL.save_image_from_URL); // 'function' is displayed

Save_image_from_URL.save_image_from_URL(); // Simple usage...
Application(s)

Statecharts

L'application My device est une application JavaFX pour la partie interface homme-machine. Le cœur de l'application est un automate de type Statecharts de Harel. L'exécution de cet automate est basé sur la bibliothèque Java PauWare. L'équivalent de PauWare en JavaScript est SCION-CORE. L'application My device, bien qu'elle puisse s'exécuter dans un browser, pose des contraintes de sécurité qu'il est de plus en plus difficile de satisfaire en regard de l'évolution des browser du marché (Firefox, Chrome, Safari, etc.).

Le travail consiste ainsi à concevoir l'interface homme-machine en HTML, CSS et JavaScript/TypeScript ainsi que réécrire le cœur de l'application avec le « moteur d'exécution » SCION-CORE sous les considérations suivantes :

Le programme Node.js de Web scraping qui suit récupère sommairement des images via le moteur de recherche Google dédié : images.google.com. Toutefois, l'« aspiration » de données sur le Web est souvent considérée comme une forme de vol d'où une sécurisation à tout-va, exemple : société DataDome. Le groupe Carrefour par exemple protège ses données via la technologie de cette société. Typiquement la requête https://www.carrefour.fr/s?q=3560070478781, bien qu'elle puisse s'exécuter via un browser (Firefox, Chrome, Safari, etc.), est plus difficile à exécuter par un « bot » qui souhaite aspirer photos, prix… voire qualités nutritionnelles, composition (produits alimentaires uniquement)… associés à un produit connu par son code barre ou GTIN (Global Trade Item Number).

En opposition à ce mouvement de sécurisation à tout-va, notre ami El Pueblo souhaite disposer d'une application capable, sur la base d'une liste de produits bien déterminés, lui dire si Carrefour Lescar, Leclerc Pau Université, Géant Casino Lons… lui garantit le prix le plus bas pour sa liste. Si une telle application aujourd'hui existe (?), elle masque peut-être le fait que les données qu'elle utilise sont payées ; en d'autres termes, des groupes comme Carrefour cherchent à (aussi) devenir des entreprises « digitales ».

Le travail consiste ainsi à adapter le programme Node.js qui suit pour tenter d'aspirer les photos des produits Carrefour. Méthode :

/* Node.js program */

const fs = require('fs'); // 'npm i @types/node' let us access to 'require', etc.

// 'puppeteer.js' library: https://developers.google.com/web/tools/puppeteer/
const puppeteer = require('puppeteer'); // 'npm install --save puppeteer' or 'sudo npm install --save puppeteer'
// Recent download problems require this: 'sudo npm install puppeteer --unsafe-perm=true --allow-root'

// 'request.js' library: https://www.npmjs.com/package/request
const request = require('request'); // 'npm install --save request' or 'sudo npm install --save request'

// Check whether 'puppeteer.js' and 'request.js' have been properly installed: 'npm list -depth=0'

class Google_Images {

    private static readonly _Database: string = './Database/';
    private static readonly _Path: string = '/search?tbm=isch&q=';
    private static readonly _URL: string = 'https://www.google.com';

    static async Take_picture() { // Returned type is inferred from 'async', i.e., 'Promise'
        const browser = await puppeteer.launch({headless: true}); // Launch 'Chrome' *WITHOUT* visual environment
        // Following call *DOES NOT* occur (because of prior 'await') until prior one terminates:
        const page = await browser.newPage();
        await page.goto(Google_Images._URL + Google_Images._Path + (typeof process.argv[2] === 'string' ? process.argv[2] : '')); // By default, 'page.goto(...)' waits for the page load event
        const photo_file_name: String = (typeof process.argv[2] === 'string' ? process.argv[2] : 'undefined') + '.png';

        let body: String = await page.evaluate(() => document.body.innerHTML);
        const start_index: number = body.search("https://encrypted-tbn0.gstatic.com");
        if (start_index !== -1) {
            let image_URL: String = body.substring(start_index);
            image_URL = image_URL.substring(0, image_URL.search("\""));
            request(image_URL).pipe(fs.createWriteStream(Google_Images._Database + photo_file_name));
        }
        else
            await page.screenshot({path: Google_Images._Database + photo_file_name}); // Default picture...
        await browser.close();
        return photo_file_name;
    }
}

Google_Images.Take_picture().then((photo_file_name) => {
    console.log('Photo file name: ' + photo_file_name);
});
Application(s)

Crisis management

L'application (ici) est un système de gestion de crise impliquant policiers et pompiers qui de façon coopérative procèdent à une intervention sur le lieu d'une crise « en cours ». Le processus de gestion de crise consiste à décider de l'envoi de voitures et de camions dont policiers et pompiers suivent l'envoi et l'arrivée jusqu'à ce que la crise soit terminée. En l'état, l'application n'a pas d'interface homme-machine. Plus précisément, un programme Java main teste l'enchaînement de crises pour vérifier grossièrement que l'application globalement fonctionne.

Le travail consiste à fabriquer une interface homme-machine en JavaFX* ou en HTML, CSS et JavaScript/TypeScript. Dans le second cas, il faut utiliser la technologie WebSockets pour pousser les données à afficher de Java au browser ; les consignes arrivent alors elles en sens inverse (des exemples de programmes WebSockets sont expliqués et disponibles ici…). Cette interface homme-machine doit permettre de se connecter en tant que policier (Police Station Coordinator) ou en tant que pompier (Fire Station Coordinator). Une fois connecté en tant que policier, seules les fonctionnalités associées au rôle de policier dans l'application sont disponibles et donc activables via l'interface homme-machine (idem pour la « connexion pompier »). Par exemple, l'instruction Java bCMS.state_fire_truck_number(2); du programme de test actuel ne doit être accessible qu'à la « connexion pompier ».

*L'outil JavaFX Scene Builder peut être intégré dans Apache NetBeans pour dessiner l'interface homme-machine. Par ailleurs, la mse en œuvre de JavaFX à partir de Java 9 demande des configurations idoines : voir aussi une telle application Java 9 ici à titre d'exemple.

Artificial Intelligence (AI)

Améliorer la technique de détection faciale ici à l'aide de techniques d'intelligence artificielle.

Application(s)

Computer Integrated Manufacturing (CIM)

Une application Node.js (cahier des charges ici… et implémentation …) écrite en TypeScript et basée sur les “frameworks” Express et @Hapi/Joi est un embryon d'architecture micro-services permettant de créer des « articles » de type « produit fini », « matière première », « pièce » et « sous-ensemble ». Au service Web de création d'article (POST), s'ajoutent deux services Web de lecture, d'un article sur sa « référence » et de tous les articles (GET).

Le travail consiste à étendre l'application via, en premier lieu, l'implantation de la base de données correspondante grâce à MongoDB, SQLite, JavaDB (script SQL JavaDB)…

En second lieu, il faut ajouter un service Web de mise à jour d'un article sur la base de sa « référence » (PUT) et un service Web de suppression d'un article sur la base de cette même « référence » (DELETE). Faire de même en suivant (création, lecture, mise à jour et suppression) pour les liens de nomenclature, les remplacements, les postes de charge, les opérations et les mouvemens de stock.

Application(s)

Bill Of Material (BOM)

L'étude de cas GPAO (ici…) donne lieu à une modélisation UML et une implémentation XML (…). Etudier les différentes technologies XML (DTD, XSD, XQuery, XSLT…) via la bibliothèque Java Saxon.

Application(s)
Pure Java

Java annotation

Ecrire une annotation Java Modifications permettant de « marquer » du code avec la date de son écriture (puis ses dates de modification), les auteurs des modifications, la description de la dernière maintenance faite via, le cas échéant (réparation uniquement), le nom d'une exception Java, la nature de cette dernière maintenance entre deux valeurs possibles (réparation et évolution fonctionnelle), l'état de la version courante entre quatre valeurs possibles (Stable, Unstable, Unchecked et Unknown). Prévoir des valeurs par défaut pour toutes les propriétés de l'annotation qui doit pouvoir être apposée sur les classes, les interfaces et les méthodes. Usages :

@Modifications(dates = {"19/06/2008","22/09/2008"}, authors = {"FB","FB"}, description = "New 'f' feature", nature = Nature.Evolution_fonctionnelle, state = State.Stable)
public class My_class { …
@Modifications(dates = {"19/06/2008","22/09/2008"}, authors = {"FB","FB"}, description = "java.lang.NullPointerException", nature = Nature.Reparation, state = State.Stable)
public class My_class { …

Procéder à la vérification run-time suivante de ce code : si la dernière maintenance est une réparation alors le nom de l'exception Java listée « existe bien » dans la machine virtuelle (astuce : Class.forName).

Application(s)

Java Naming and Directory Interface (JNDI)

Les sites Web “WHOIS” aident à la recherche des propriétés des noms de domaine. Ils s'appuient sur des serveurs Domain Name Service (DNS) en charge de ce travail. Ces serveurs sont en général libres d'accès comme, par exemple, celui de Google : dns://8.8.8.8. Le programme Java ci-dessous basé sur la technologie Java Naming and Directory Interface (JNDI) recherche des informations sur des noms de domaine comme FranckBarbier.com, etc. Chaque nom de domaine a un certain nombre de “records” (voir aussi ici…) qu'il est possible d'interroger.

package com.FranckBarbier.Java.JNDI_DNS;

import javax.naming.*;
import javax.naming.directory.*;

public class JNDI_DNS {

    public JNDI_DNS() {
        try {
            java.util.Properties _p = new java.util.Properties();
            // For Java 9 and more: https://mvnrepository.com/artifact/com.sun.jndi/dns:
            _p.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory");
            // Use another DNS server (platform config. otherwise: https://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-dns.html#URL):
            // _p.setProperty(Context.PROVIDER_URL, "dns://194.167.156.13"); // UPPA
            // _p.setProperty(Context.PROVIDER_URL, "dns://8.8.8.8"); // Google
            // _p.setProperty(Context.PROVIDER_URL, "dns://193.146.78.14"); // University of Mondragon
            DirContext dc = new InitialDirContext(_p);
            Attributes attributes = dc.getAttributes("FranckBarbier.com", new String[]{"NS"}); // Stores the name server for a DNS entry...
            if (attributes != null) {
                NamingEnumeration ne = attributes.get("NS").getAll();
                while (ne.hasMoreElements()) {
                    System.out.println("[NS] entry: " + ne.next().toString());
                }
            }
// Get all Web address suffixes:
            InitialContext _ic = new InitialContext(_p);
            System.out.println("\nInitial context: " + _ic.getNameInNamespace());
            NamingEnumeration ne = _ic.list("");
            while (ne.hasMore()) {
                System.out.println("\t" + ((NameClassPair) (ne.next())).getName());
            }

            NameParser np = _ic.getNameParser(_ic.getNameInNamespace());
            Name university_of_Mondragon = np.parse("www.mondragon.edu");
            System.out.print("\nwww.mondragon.edu has " + university_of_Mondragon.size() + " components:");
            for (int i = 0; i < university_of_Mondragon.size(); i++) {
                System.out.print("\t" + university_of_Mondragon.get(i));
            }
            Object o = _ic.lookup(university_of_Mondragon.getPrefix(university_of_Mondragon.size() - 1));
            ne = (((com.sun.jndi.dns.DnsContext) o).getAttributes(university_of_Mondragon, null)).getAll();
            while (ne.hasMore()) {
                BasicAttribute ba = (BasicAttribute) ne.next();
                System.out.print("\n\tAttribute id. [" + ba.getID() + "]: ");
                NamingEnumeration nee = ba.getAll();
                while (nee.hasMore()) {
                    System.out.print("\t" + nee.next());
                }
            }
            System.out.println("\n\nClosing...");
            _ic.close();
        } catch (NamingException ne) {
            System.err.println(ne.getMessage() + ": " + ne.getExplanation());
        }
    }

    public static void main(String[] args) {
        new JNDI_DNS();
    }
}

Le but du travail est d'utiliser la technologie JNDI comme une technologie « serveur » dans le cadre d'une application Web de type “WHOIS”. Via une interface homme-machine HTML/CSS à imaginer, l'utilisateur peut obtenir tout type d'informations via un nom de domaine saisi par lui.

Pour communiquer les données trouvées par Java (après exécution de requêtes JNDI) à JavaScript, la technologie WebSockets (des archétypes de collaboration sont expliqués et disponibles ici…) est mise en œuvre. De même, JavaScript envoie à Java les ordres de recherche en format JSON (traiter des données JSON avec Java est expliqué ici…).

Application(s)
Enterprise JavaBeans™ (EJB)

Apache NetBeans tutorial on Java EE

Enterprise JavaBeans™ (EJB), “entity” versus “session”

A simple Java EE application is based on a Stateless Session Bean named Customer_management interacting with an Entity Bean named Customer.

Customer_management.zip is the “server” program while Customer_management_client.zip is the “client” program. Banking_system.Derby.sql is the JavaDB database SQL script.

The proposed work consists in extending this application so that it supports CRUD (-Create, Read, Update, Delete-) functions for the Logical_card table in the database (please keep the database schema “as is”).

Enterprise JavaBeans™ (EJB), “local” versus “remote” interface

Given Asterix and Obelix as two collaborative Session Beans. Asterix has a business method named strength, which itself calls a business method offered by Obelix also named strength.

  1. Implement Asterix and Obelix in the same EJB module as follows:
    • Both are Stateless Session Beans (use the following annotation value for Obelix: mappedName = "ejb/Obelix")
    • Dependency injection in Asterix to Obelix as follows: @javax.ejb.EJB(mappedName = "ejb/Obelix") Obelix o = null;
    • Call of Obelix strength in Asterix strength: o.strength();
  2. Implement Asterix and Obelix in two different EJB modules. Change the code in both Asterix and Obelix so that strength in Asterix is still able to call strength in Obelix.
Application(s)

Enterprise JavaBeans™ (EJB), exercice 1

Soit le code EJB qui suit. S1 et S2 sont dans le même EJB module.

@javax.ejb.Stateless
public class S1 {
    private int _i;
    public void increment() {
        _i++;
    }
    public int get_i() {
        return _i;
    }
}
@javax.ejb.Singleton
@javax.ejb.Startup
public class S2 {
    @javax.ejb.EJB
    private S1 _s1;
    @javax.ejb.EJB
    private S1 _s1_bis;
    @javax.annotation.PostConstruct
    public void g() {
        int result = 0;
        _s1.increment();
        result += _s1.get_i();
        _s1.increment();
        result += _s1.get_i();
        System.out.println("result (g): " + result);
    }
    public void h() {
        int result = 0;
        _s1.increment();
        result += _s1.get_i();
        _s1_bis.increment();
        result += _s1_bis.get_i();
        System.out.println("result (h): " + result);
    }
}
  1. Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
    1. rien n’est affiché
    2. est affiché un entier positif ou nul
    3. est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
    4. est affiché 3 exactement dans tous les cas d’exécution
    5. est affiché 2 exactement dans tous les cas d’exécution
  2. L’annotation @javax.annotation.PostConstruct est placée sur la méthode h dans S2 (et supprimée sur la méthode g). Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
    1. rien n’est affiché
    2. est affiché un entier positif ou nul
    3. est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
    4. est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
    5. est affiché 3 exactement dans tous les cas d’exécution
    6. est affiché 2 exactement dans tous les cas d’exécution
  3. L’annotation @javax.ejb.Stateless sur S1 est remplacée par @javax.ejb.Stateful et l’annotation @javax.annotation.PostConstruct est mise sur la méthode g dans S2. Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
    1. rien n’est affiché
    2. est affiché un entier positif ou nul
    3. est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
    4. est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
    5. est affiché 3 exactement dans tous les cas d’exécution
    6. est affiché 2 exactement dans tous les cas d’exécution
  4. L’annotation @javax.ejb.Stateless sur S1 est remplacée @javax.ejb.Stateful et l’annotation @javax.annotation.PostConstruct est sur la méthode h dans S2. Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
    1. rien n’est affiché
    2. est affiché un entier positif ou nul
    3. est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
    4. est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
    5. est affiché 3 exactement dans tous les cas d’exécution
    6. est affiché 2 exactement dans tous les cas d’exécution

Enterprise JavaBeans™ (EJB), exercice 2

Dans le code EJB qui suit (MDB.EJB.zip ), Starter et Dispatcher sont dans le même EJB module alors que Service est dans un autre EJB module.

Le développeur souhaite voir affiché dans le log du serveur : « To be or not to be, this is the question… ». Malheureusement, ce n'est pas le cas. Modifier le programme pour obtenir ce résultat.

Note : la création de ressources JMS avec asadmin est expliquée ici

public class My_message implements java.io.Serializable {
    final String _word;
    public String getWord() {
        return _word;
    }
    final int _order;
    public int getOrder() {
        return _order;
    }
    My_message(String content, int order) {
        _word = content;
        _order = order;
    }
}
/***************************************/
public interface Service {
    void construct_sentence(My_message my_message);
    void display_sentence();
    boolean stop();
}
/***************************************/
@javax.ejb.Local({Service.class})
@javax.ejb.Stateful
public class Service_implementation implements Service {
    private final java.util.Vector<String> _sentence = new java.util.Vector<>();
    public void construct_sentence(My_message my_message) {
        if (my_message.getOrder() + 1 > _sentence.size()) _sentence.setSize(my_message.getOrder() + 1);
        _sentence.set(my_message.getOrder(), my_message.getWord());
    }
    public void display_sentence() {
        String sentence = "";
        for (String word : _sentence) sentence += word;
        System.out.println(sentence);
    }
    public boolean stop() {
        int n = 0;
        for (String word : _sentence)
            if (word != null) n++;
        return n == Starter.Number;
    }
}
/***************************************/
@javax.ejb.MessageDriven(activationConfig = {@javax.ejb.ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/MY_QUEUE"), @javax.ejb.ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")})
public class Dispatcher implements javax.jms.MessageListener {
    @javax.ejb.EJB
    private Service _service = null;
    @Override
    public void onMessage(javax.jms.Message message) {
        try {
            My_message my_message = (My_message) ((javax.jms.ObjectMessage) message).getObject();
            _service.construct_sentence(my_message);
            if (_service.stop()) _service.display_sentence();
        } catch (Exception e) { // Error... }
    }
}
/***************************************/
@javax.ejb.Singleton
@javax.ejb.Startup
public class Starter {

    public static final int Number = 10;

    private javax.jms.QueueConnectionFactory _queue_connection_factory;
    private javax.jms.Queue _queue;
    private javax.jms.QueueConnection _queue_connection;
    private javax.jms.QueueSession _queue_session;
    private javax.jms.QueueSender _queue_sender;

    @javax.annotation.PostConstruct
    public void create() {
        try {
            javax.naming.Context _jndi_context = new javax.naming.InitialContext();
            _queue_connection_factory = (javax.jms.QueueConnectionFactory) _jndi_context.lookup("jms/MY_QUEUE_FACTORY");
            _queue = (javax.jms.Queue) _jndi_context.lookup("jms/MY_QUEUE");
            _queue_connection = _queue_connection_factory.createQueueConnection();
            _queue_session = _queue_connection.createQueueSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
            _queue_sender = _queue_session.createSender(_queue);
            int i = 0;
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("To ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("be ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("or ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("not ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("to ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("be, ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("this ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("is ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("the ", i++)));
            _queue_sender.send(_queue_session.createObjectMessage(new My_message("question...", i++)));
            assert (i == Number);
        } catch (Exception e) { // Error... }
    }
}

Enterprise JavaBeans™ (EJB), exercice 3

Dans le code EJB qui suit, toute instance d’EJB My_stateful maintient une liste de références (champ _collection_of_My_stateless_remote) sur une collection d’EJBs My_stateless.

public interface My_stateless_remote {
    void business();
}
…
@javax.ejb.Stateless
public class My_stateless implements My_stateless_remote {
    @Override
    public void business() {
        // Any business code here
    }
}
public interface My_stateful_remote {
    void business();
}
…
@javax.ejb.Stateful
@javax.ejb.Remote(My_stateful_remote.class)
public class My_stateful {
    private java.util.Collection<My_stateless_remote> _collection_of_My_stateless_remote;
    // Le code des questions s’ajoute ici…
}
  1. Est-ce que ce lien (cette liste de réf.) est susceptible de causer des erreurs à l’exécution ?
  2. Est-ce que ce lien est susceptible d’améliorer la performance à l’exécution ?
  3. En EJB, il n’est pas possible de faire une injection de ressource sur une collection. En d’autres termes, ce code ne fonctionne pas :
    // '@javax.ejb.EJB' est mise en commentaires car ne fonctionne pas...
    private java.util.Collection<My_stateless_remote> _collection_of_My_stateless_remote;

    Pour pallier le problème, on « capture » les composants différemment (ce code s'ajoute au code préalable) :

    My_stateful() throws Exception {
        javax.naming.Context jndi_context = new javax.naming.InitialContext();
        for (int i = 0; i < 10; i++) {
            My_stateless_remote msr = (My_stateless_remote) jndi_context.lookup("java:global/My_EJB_module/My_stateless"); // 'My_EJB_module' is the name of the deployment file
            _collection_of_My_stateless_remote.add(msr);
        }
    }
    Bien que ce code fonctionne, quelle est une meilleure alternative ?
  4. Soit la méthode business dans la classe My_stateful (ce code s'ajoute au code préalable) :
    public void business() {
        for (My_stateless_remote msr : _collection_of_My_stateless_remote)
            msr.business();
    }
    Bien que ce code fonctionne, quelle est une meilleure alternative ?

Enterprise JavaBeans™ (EJB), exercice 4

Répondre aux questions figurant dans ce document en fonction de l'application EJB Premiers.EJB.zip .

Enterprise JavaBeans™ (EJB), exercice 5

Implémenter le programme Lotto! en EJB sous les contraintes suivantes :

  1. Tirer_un_chiffre est un composant assurant un seul service tirer retournant un chiffre dans un intervalle [1-borne].
  2. Tirer_tous_les_chiffres (dont le mappedName est "Loto") est un composant assurant un service tirer établissant un tirage de 48 chiffres différents dans l'intervalle [1-49]. Une autre business method stocker envoie le résultat du tirage dans une file d'attente JMS. Tirer_tous_les_chiffres utilise Tirer_un_chiffre.
  3. Faire un programme de test qui appelle tirer puis stocker sur "Loto".
Application(s)

Enterprise JavaBeans™ (EJB) with JavaServer Faces (JSF)

The New York City Penitentiary (NYCP) case study results from a long interview between the NYCP director and a business analyst. From this discussion, a UML Use Case Diagram including 5 concrete business services and a UML Class Diagram are provided. Beyond, several software artifacts are produced (e.g., a JavaDB database SQL script, static Web pages as requirements' illustration…).

Complete the current Web application with two Web pages: Add_offense.xhtml and Offenses.xhtml. Add_offense.xhtml has to be attainable from All_prisoners.xhtml by means of a Add offense hyperlink. Add_offense.xhtml aims at adding a link to the Prisoner (participant role) - Criminal case (offense role) association. Once done, Offenses.xhtml displays all of the criminal cases in which a prisoner is involved, including, of course, the very last (just added) offense. Behavior of Add_offense.xhtml and Offenses.xhtml has to be similar to the existing Add_participant.xhtml and Participants.xhtml Web pages.

Web Services

The Railcar control system application is a Java EE application. At this time, the client program is a simplified Java SE program that graphically displays the status of the railcars and the terminals. For that, the client program continuously requests the Java EE (server-side) program to ask for the status of railcars and the terminals. However, two Web services offered by the server-side program are not yet used.

@javax.jws.WebService(serviceName = "Railcar_new_destination")
@javax.ejb.Stateless()
public class Railcar_new_destination {
    @javax.ejb.EJB
    private Control_center_local _control_center = null;

    @javax.jws.WebMethod(operationName = "railcar_new_destination")
    @javax.jws.Oneway
    public void railcar_new_destination(@javax.jws.WebParam(name = "railcar") String railcar, @javax.jws.WebParam(name = "terminal") String terminal) {
        assert (_control_center != null);
        _control_center.railcar_new_destination(railcar, terminal);
    }
}

@javax.jws.WebService(serviceName = "Terminal_new_destination"
@javax.ejb.Stateless()
public class Terminal_new_destination {
    @javax.ejb.EJB
    private Control_center_local _control_center = null;

    @javax.jws.WebMethod(operationName = "terminal_new_destination")
    @javax.jws.Oneway
    public void terminal_new_destination(@javax.jws.WebParam(name = "terminal") String terminal, @javax.jws.WebParam(name = "another_terminal") String another_terminal) {
        assert (_control_center != null);
        _control_center.terminal_new_destination(terminal, another_terminal);
    }
}

Railcar_new_destination means that a new destination has been requested in a given railcar to stop at a given terminal. Terminal_new_destination means that a new destination has been requested in a given terminal to stop at another given terminal.

The work consists in building a browser-based user interface that is able to:

Note: at this time, identities of Web services requesters are not managed. Other adaptations/extensions are also required so that the existing server-side program manages passengers in a consistent way. Otherwise, the exposure of the Java EE program, in terms of architecture especially, is probably unfit for calls from a browser. More precisely, it is imposed that all Web services run in a RESTful mode and carried data are based on JSON.