Homework



Headlines
Numbers… (and their representation)

Bar code

Implanter en C++ et/ou Java et/ou Python et/ou TypeScript le « check sum » here… d'un code barre. Le format le plus connu est défini sur 13 chiffres (e.g., 3200000003774). Le 13e et dernier chiffre est le chiffre de contrôle.

Effectuer le travail demandé en téléchargeant les applications pré-structurées ci-dessous.

Ensuite, concernant Java, tester le code prédéfini here

Application(s)
private _compute_check_sum(): number {
    // Méthode : https://fr.wikipedia.org/wiki/EAN_13#Calcul_de_la_cl%C3%A9_de_contr%C3%B4le_EAN_13
    // '471-9-5120-0288-x' with 'x' as check sum (i.e., 'x === 9')
    // '7', '9', '1', '0', '2', '8':
    const remainder = (this._bar_code.filter((element: number, index: number) => index % 2 !== 0)
                .reduce((result, element) => result + 3 * element, 0) +
        // '4', '1', '5', '2', '0', '8':
        this._bar_code.filter((element: number, index: number) => index % 2 === 0 && index !== Bar_code.Thirteen - 1)
                .reduce((result, element) => result + element, 0)) % 10;
    return remainder === 0 ? 0 : 10 - remainder;
}

Bar code++

En TypeScript, récupérer des images de produits alimentaires en s'inspirant de l'application Shopping.ts.zip ou en utilisant l'API de Open Food Facts here… Vérifier en suivant à l'aide de QuaggaJS que le code barre sur l'image est correct.

Pour démarrer, copier le lien de l'image ci-dessus pour la visualiser dans un navigateur en vue de la télécharger. Tester QuaggaJS avec cette image puis généraliser en récupérant des images sur Open Food Facts.

Application(s)

N°INSEE

Implanter en C++ et/ou Java et/ou Python et/ou 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) et que sa clef est saisie simultanément pour contrôle (e.g., 97 - (1630125388055 % 97) == 29).

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 here… Tutoriel Java there

En 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.ts) faisant le calcul et l'autre (Main.ts) 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 TypeScript malgré ce qui est annoncé sur le site Web.

Application(s)
Temporal data

Leap year

Implanter en C++ et/ou Java et/ou Python et/ou TypeScript dans une classe Leap_year_UTILITY une fonction booléenne établissant si, oui ou non, une année est bissextile (leap year en anglais).

La fonction doit prendre en paramètre une date sous forme de chaîne de caractères. Il y a donc lieu dans un premier temps de convertir la date dans un type gérant les dates (tutoriel en Java here…). En TypeScript, la date est fournie dans le type primitif string puis transformée dans le type Date en vue d'établir si la date est bissextile (indication : Date.parse).

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 here).

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);
Application(s)

Yesterday, tomorrow…

Un programme C++ « agé » détermine en fonction du temps machine si une date donnée est « Hier », « Demain »….

Implanter en Java et/ou Python et/ou TypeScript un programme équivalent en y ajoutant les fonctionnalités : « prochain vendredi », « mardi précédent », etc.

Pour Java, il y a lieu de mettre en œuvre l'API java.time qui a complètement été revue en Java 8 (tutoriel here).

// Yesterday_Tomorrow.h
#ifndef _Yesterday_Tomorrow
#define _Yesterday_Tomorrow
#include <string>

class Yesterday_Tomorrow {
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;

    Yesterday_Tomorrow(int, int, int, std::string&);
};
#endif

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

#include <iostream>
#include <string>

#include "Yesterday_Tomorrow.h"

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

Yesterday_Tomorrow::Yesterday_Tomorrow(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_structure_de_donnees = 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_structure_de_donnees->tm_mday;
    auto mois_systeme = maintenant_structure_de_donnees->tm_mon + 1; // Attention : 'tm_mon' retourne le mois système moins '1' !
    auto annee_systeme = maintenant_structure_de_donnees->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;
    Yesterday_Tomorrow Yesterday_Tomorrow(9, 5, 2019, resultat);
    std::cout << resultat << std::endl;

    return 0;
}
Application(s)
Predefined versus user-defined types

Lotto!

Implanter en C++ et/ou Java et/ou Python et/ou 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) au cas où ce nombre aurait déjà été tiré…

public class Main {
    public static void main(String parameters[]) {
        Loto l = new Loto();
        l.tirer();
        System.out.println(l.toString());
    }
}
…
public class Loto {
    private final java.util.ArrayList<Integer> _boules = new java.util.ArrayList<>(java.util.Arrays.asList(
            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, 29, 30,
            31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48, 49
    ));
    public void tirer() {
        java.util.Collections.shuffle(_boules, new java.util.Random());
    }
    @Override
    public String toString() {
        String resultat = "";
        for (int i : _boules) // A faire : enlever le dernier élément pour avoir exactement 8 grilles de 6 = 48
            resultat += '\t' + Integer.toString(i);
        return resultat;
    }
}
Application(s)

Color

Implanter en C++ et/ou Java et/ou Python et/ou 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 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 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 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 TypeScript, appliquer les mêmes règles que pour Java et créer l'interface homme-machine dans une page Web avec HTML-CSS.

Application(s)
Array, dictionary…

Feature detection

Ce travail concerne les tableaux JavaScript (type Array : doc. here…) 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.

En préambule au post-processing, le logiciel de détection de caractéristiques est actuellement écrit en JavaScript, il faut le télécharger puis l'adapter en TypeScript (Character.jsCharacter.ts et Feature_detection.jsFeature_detection.ts) avant d'implanter de nouvelles heuristiques.

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 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 : here). 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)
Generics

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 en C++ 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.

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

En 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 here 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 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 here 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 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 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 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 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)
Security

RSA algorithm

L'algorithme RSA est un algorithme de cryptage basé sur des mathématiques (fichier PDF here…). 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 TypeScript, utiliser l'API fetch here… 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 here. 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 à TypeScript grâce à la technologie WebSockets (des archétypes de collaboration sont expliqués et disponibles here…). 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 here…, par exemple :

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

Promise

L'application graphique 3D Man head qui suit met un certain temps avant visualisation. La bonne pratique est l'insertion d'une animation de type « sablier » pour signaler à l'utilisateur que l'application est en cours de chargement. Typiquement ici, c'est la géométrie de la tête d'homme qui prend du temps de chargement. Dans ce contexte, la librairie Splash Screen here fournit une animation de type « attente » dès lors que le chargement d'une page Web est sujette à un délai.

Le travail consiste à améliorer le code de l'application : la « promesse » (objet de type Promise) incarnant le chargement de la tête d'homme, une fois tenue, doit donner lieu à la disparition de l'animation d'attente (e.g., le sablier disparaît) et à l'apparition de l'animation 3D proprement dite. L'apparition de l'animation d'attente (e.g., le sablier apparaît) doit elle être coordonnée à la promesse window.DOM_ready.

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 souhaite avec la souris pouvoir effectuer une pause du compte à rebours en cours ; on le reprend à la demande.
  2. On souhaite aussi 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' */, texture => {
    const bus = this._scene.getObjectByName(this._image_URL);
    bus.material.map = texture;
    bus.material.needsUpdate = true;
});
Application(s)

Obama versus Trump

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 :

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' OK!
            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 complete_response = new Promise(result => {
    const response = window.document.getElementById("response") as HTMLInputElement;
    response.addEventListener('change', (event: Event) => {
        // L'événement 'change' est produit par JavaScript lorsque l'utilisateur a tapé "Return"...
        if (Game.Data[character].Answer.test((event.target as HTMLInputElement).value)) // RegExp
            result("gained");
        else
            result("lost");
    });
});

Il faut faire de même avec le temps restant (timer armé et désarmé) ainsi que l'événement 'input' de la même balise input. Au final, est affiché “gained” ou “lost” sur l'image selon que la réponse est correcte ou que le temps restant soit écoulé (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 (TypeScript) ainsi que réécrire le cœur de l'application avec le « moteur d'exécution » SCION-CORE sous les considérations suivantes :

Web scraping

L'application Node.js de Web scraping (dont le code TypeScript 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, qualités nutritionnelles, composition (produits alimentaires uniquement)… attributs associés à un produit parfaitement identifié par son code barre ou Global Trade Item Number -GTIN-.

/* 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);
});

En opposition à ce mouvement de sécurisation à tout va, on souhaite disposer d'une application capable, sur la base d'un produit identifié par son code barre, de donner l'offre de Carrefour (voire Carrefour Lescar), E.Leclerc (voire E.Leclerc Pau Université), Casino (voire Géant Casino Lons)… sur ce produit : photo, prix, prix au kilo…

Le travail consiste à construire cette application en Java avec la bibliothèque jsoup (ou toute autre). L'idée est de récupérer des informations comme la photo, le prix, le prix au kilo… mais aussi d'autres (e.g., « sans gluten ? ») selon la méthode suivante : effectuer des requêtes via un browser (e.g., https://www.carrefour.fr/s?q=3083681093926, https://www.carrefour.fr/s?q=Nutella) puis analyser le contenu de la page Web retournée.

Par exemple, où sont les liens vers les (URLs des) images ? Via l'utilisation d'expressions régulières here…, délimiter les URLs des images puis sauver alors les images localement sur disque. Indication :

Application(s)

Crisis management

Une application Java here 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 notamment à décider de l'envoi de voitures de police et de camions de pompier dont une cellule de coordination « policier » Police Station Coordinator -PSC- et une cellule de coordination « pompier » Fire Station Coordinator -FSC- suivent l'envoi et l'arrivée jusqu'à ce que la crise soit terminée.

En l'état, l'application est une application Java sans interface homme-machine et avec base de données embarquée. Plus largement, un programme Java main teste l'enchaînement de crise(s) pour vérifier grossièrement que l'application (dans sa globalité) fonctionne.

Le travail consiste à fabriquer une interface homme-machine en JavaFX* ou HTML-CSS (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 (un exemple de programme WebSockets est expliqué et disponible here…). 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 here à titre d'exemple.

Artificial Intelligence -AI-

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

Application(s)

Product Lifecycle Management -PLM-

Une application Node.js (cahier des charges here… et implémentation there…) écrite en TypeScript et basée sur les “frameworks” Express et 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 ou encore JavaDBSQL script .

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)
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 at 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” here… 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 here…) est mise en œuvre. De même, JavaScript envoie à Java les ordres de recherche en format JSON (exemple de traitement des données JSON avec Java here…).

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.

The proposed work consists in extending this application so that it supports Create, Read, Update, Delete -CRUD- 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.

The issue of about the exposure of Obelix between javax.ejb.LocalBean, javax.ejb.Local, and javax.ejb.Remote.

  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 = "OBELIX")
    • Dependency injection in Asterix to Obelix as follows: @javax.ejb.EJB(mappedName = "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 : création de ressources JMS avec asadmin here

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 REpresentational State Transfer -RESTful- mode and carried data are based on JSON.