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 formatlong long
, e.g.,long long n_insee_de_Franck_Barbier = 1630125388055LL;
(ne pas oublier le suffixeLL
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 conversionstd::atoll
(#include <cstdlib>
) pour convertir des chaînes de caractères en variables de typelong 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, utiliserexport
et le second utiliserimport
.
Note : il semble que la réutilisation de SweetAlert2 viaimport
ne fonctionne pas en TypeScript malgré ce qui est annoncé sur le site Web.Application(s)
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 typeDate
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'APIjava.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)
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 :
- C++ : les fonctions
std::srand(unsigned int)
etstd::rand()
(#include <cstdlib>
)- Java : la classe
java.util.Random
ou la fonction prédéfinieMath.random()
- TypeScript : la fonction
Math.random()
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
Account, Real
FUNCTIONS
“accessor”
balance: Account → Real
overdraft: Account → Real
“modifier”
deposit: Account × Real → Account
withdraw: Account × Real ↛ Account
“constructor”
new: Real × Real → Account
AXIOMS
a: Account, i: Real, balance(a) + i = balance(deposit(a,i))
a: Account, i: Real, balance(a) - i = balance(withdraw(a,i))
i, j: Real, balance(new(i,j)) = i
i, j: Real, overdraft(new(i,j)) = j
a: Account, overdraft(a) >= 0
PRE-CONDITIONS
a: Account, i: Real, pre(withdraw(a,i)) = (i - balance(a) <= overdraft(a))
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 :
Min: Temperature → tMin
La fonction
Min
est basée sur l'axiome suivant :
t: Temperature, asCelsius(Min(t)) = –273.15
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 :
asCelsius: Temperature → Real
asFahrenheit: Temperature → Real
asKelvin: Temperature → Real
Les deux axiomes suivants s'appliquent :
t: Temperature, asKelvin(t) = asCelsius(t) - asCelsius(Min(t))
t: Temperature, asFahrenheit(t) = 9/5 * asCelsius(t) + 32.
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)
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 fonctionthen
permet d'accéder à un tableaueyes
;eyes.length
est alors le nombre d'yeux trouvés. Au-delà,eyes[0].x
eteyes[0].y
représentent le coin supérieur gauche du rectangle bornant le premier œil alors queeyes[0].width
eteyes[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.js
⇝Character.ts
etFeature_detection.js
⇝Feature_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 dex
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
.
- Pour Java, on peut opportunément réutiliser la méthode
Collections.sort
ou se débrouiller pour que les degrés dex
soient rangés de façon ascendante dans le dictionnaire here.- Pour TypeScript, on peut opportunément réutiliser la fonction
sort
sur les tableaux pour obtenir cet ordre. En l'occurrence, le programmeHorner.ts
ci-après utilise la variablepolynomial
comme un tableau d'objets, i.e.,polynomial.push({coefficient: …, power: …});
. Réviser ce programme en utilisant un dictionnaire (Map) TypeScript.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. Sig
est une géométrie alorsg.vertices
etg.faces
sont deux tableaux de typeArray
. Une face est composée de trois sommets exactement. Sif
est une face alorsf.a
,f.b
etf.c
sont des index dans le tableau de sommets. A titre d'illustration,g.vertices[f.a]
est un des trois sommets de la facef
.Before processing
L'application 3D qui suit montre la géométrie de lèvres reconstruite. En fait, les tableaux
vertices
etfaces
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)
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ériquetemplate<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énementinput
, 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)
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 classeCurrency
ainsi que ses descendantes. Construire en suivant les classesMoroccan_Dirham
etDollar
. Dans une autre branche de la hiérarchie, construire la classeBitcoin
comme sous-classe d'une classeCrypto_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 classeCurrency
ainsi que ses descendantes. Construire en suivant les classesMoroccan_Dirham
etDollar
. Dans une autre branche de la hiérarchie, construire la classeBitcoin
comme sous-classe d'une classeCrypto_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 classeMessage
. En effet, tant C++ (std::bitset
) que Java (java.util.BitSet
) proposent des composants logiciels capables de « motoriser » la classeMessage
.Revoir en C++ et/ou Java et/ou Python et/ou TypeScript la classe C++
Message
.
- Pour C++, trouver une manière simple de « mimer » le type
Bit
existant puis éliminer dans la mesure du possible les classesLimited_bit_stream
etUnlimited_bit_stream
.- Pour Java, redéfinir la méthode
toString
des classes JavaBit
etMessage
en s'inspirant de l'exemple qui suit (attention : faut-il utiliser ou non l'héritage ?).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 classeNote
montre l'impossibilité de redéfinir des méthodes déclaréesprivate
en Java. Il en résulte qu'une méthode déclaréeprivate
en Java est implicitementfinal
, 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 :
- Les « légumes-feuilles » : céleri, chou, épinard, fenouil, oseille…
- Les salades sont une catégorie particulière des légumes-feuilles sachant que la laitue est une salade ;
- Les « légumes-tiges » : poireau, asperge, pousses de bambous…
- Les « légumes-fleurs » : artichaut, chou-fleur, brocoli…
- Les « légumes-racines » : betterave, carotte, navet, radis…
- Les bulbes : ail, échalote, oignon ;
- Les légumes secs, dont on consomme les graines : fève, haricots secs, lentilles, petit pois, pois chiche, soja ;
- Les « légumes-fruits », consommés en tant que légumes, mais constituant le fruit, au sens botanique, de la plante : aubergine, tomate, concombre, courge…
- Les « fines herbes », utilisées comme condiments : cerfeuil, persil, estragon, ciboulette, laurier, basilic…
- Les tubercules : patate douce, pomme de terre, topinambour… sont des légumes du point de vue biologique mais non du point de vue nutritionnel où ils sont considérés comme des féculents.
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'interfaceVegetable
et le type « légumes-feuilles ». Créer en suivant une classe génériqueSoup_recipe
possédant unSet
deVegetable
.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)
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)
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 :
- Utiliser JavaFX,
- 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 promessewindow.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 :
- On souhaite avec la souris pouvoir effectuer une pause du compte à rebours en cours ; on le reprend à la demande.
- 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 baliseinput
: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 baliseinput
. 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 :
- La notation
do/
dans l'étatS32
n'est pas supportée par SCION-CORE ; on peut la remplacer parentry/
.- SCION-CORE ne supporte pas les invariants :
[port.isOpen()]
et[port.isClose()]
sont donc non transposables…- Dans
S22
,^self.request h
est un auto-envoi d'événement (i.e., la machine à états s'envoie un événement à elle-même) qui est aussi non supporté par SCION-CORE ; on peut par exemple s'en sortir comme cela :window.dispatchEvent(new Event('request h'));
puis…- SCION-CORE ne dispose pas de fonction
stop
pour arrêter une machine à états.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 :
- Exemple (Carrefour) de (sous-)chaîne de caractères trouvée :
'/media\/1500x1500\/Photosite\/PGC\/EPICERIE\/3560070478781_PHOTOSITE_20171208_164121_0.jpg?placeholder='
- Expressions régulière « compatible » :
'\/media\\\/\d+x\d+\\\/(\b\w+\b\\\/)+'
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
*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.bCMS.state_fire_truck_number(2);
du programme de test actuel ne doit être accessible qu'à la « connexion pompier ».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 JavaDB ⤳ SQL script .
- Ex. d'application TypeScript, Node.js, Mongoose, and MongoDB
- Ex. d'application TypeScript, Node.js, TypeORM, and SQLlite
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
etUnknown
). 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 commeFranckBarbier.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 namedCustomer
.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
andObelix
as two collaborative Session Beans.Asterix
has a business method namedstrength
, which itself calls a business method offered byObelix
also namedstrength
.The issue of about the exposure of
Obelix
betweenjavax.ejb.LocalBean
,javax.ejb.Local
, andjavax.ejb.Remote
.
- Implement
Asterix
andObelix
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
toObelix
as follows:@javax.ejb.EJB(mappedName = "OBELIX") Obelix o = null;
- Call of
Obelix
strength
inAsterix
strength
:o.strength();
- Implement
Asterix
andObelix
in two different EJB modules. Change the code in bothAsterix
andObelix
so thatstrength
inAsterix
is still able to callstrength
inObelix
.Application(s)
Enterprise JavaBeans™ (EJB), exercice 1
Soit le code EJB qui suit.
S1
etS2
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); } }
- Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
- rien n’est affiché
- est affiché un entier positif ou nul
- est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
- est affiché 3 exactement dans tous les cas d’exécution
- est affiché 2 exactement dans tous les cas d’exécution
- L’annotation
@javax.annotation.PostConstruct
est placée sur la méthodeh
dansS2
(et supprimée sur la méthodeg
). Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
- rien n’est affiché
- est affiché un entier positif ou nul
- est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
- est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
- est affiché 3 exactement dans tous les cas d’exécution
- est affiché 2 exactement dans tous les cas d’exécution
- L’annotation
@javax.ejb.Stateless
surS1
est remplacée par@javax.ejb.Stateful
et l’annotation@javax.annotation.PostConstruct
est mise sur la méthodeg
dansS2
. Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
- rien n’est affiché
- est affiché un entier positif ou nul
- est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
- est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
- est affiché 3 exactement dans tous les cas d’exécution
- est affiché 2 exactement dans tous les cas d’exécution
- L’annotation
@javax.ejb.Stateless
surS1
est remplacée@javax.ejb.Stateful
et l’annotation@javax.annotation.PostConstruct
est sur la méthodeh
dansS2
. Au déploiement de l’EJB module, que se passe-t-il ? Répondre en choisissant parmi les hypothèses suivantes :
- rien n’est affiché
- est affiché un entier positif ou nul
- est affiché un entier ne pouvant varier que dans l’intervalle [0..2]
- est affiché un entier ne pouvant varier que dans l’intervalle [0..3]
- est affiché 3 exactement dans tous les cas d’exécution
- 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
etDispatcher
sont dans le même EJB module alors queService
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’EJBsMy_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… }
- Est-ce que ce lien (cette liste de réf.) est susceptible de causer des erreurs à l’exécution ?
- Est-ce que ce lien est susceptible d’améliorer la performance à l’exécution ?
- 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 :
Bien que ce code fonctionne, quelle est une meilleure alternative ?// '@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); } }
- Soit la méthode
business
dans la classeMy_stateful
(ce code s'ajoute au code préalable) :Bien que ce code fonctionne, quelle est une meilleure alternative ?public void business() { for (My_stateless_remote msr : _collection_of_My_stateless_remote) msr.business(); }
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 :
Tirer_un_chiffre
est un composant assurant un seul servicetirer
retournant un chiffre dans un intervalle[1-borne]
.Tirer_tous_les_chiffres
(dont lemappedName
est"Loto"
) est un composant assurant un servicetirer
établissant un tirage de 48 chiffres différents dans l'intervalle[1-49]
. Une autre business methodstocker
envoie le résultat du tirage dans une file d'attente JMS.Tirer_tous_les_chiffres
utiliseTirer_un_chiffre
.- Faire un programme de test qui appelle
tirer
puisstocker
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
andOffenses.xhtml
.Add_offense.xhtml
has to be attainable fromAll_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 ofAdd_offense.xhtml
andOffenses.xhtml
has to be similar to the existingAdd_participant.xhtml
andParticipants.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:
- call on demand the above two Web services with parameters entered through the user interface. These two Web services are probably not rich enough at this time in terms of parameters and returned values. In other words, adaptations/extensions are required.
- get at initialization time, the entrance terminals (their names especially). On purpose, an additional dedicated Web service must be developed.
- get (in a cyclic way, through a timer for instance) the status (on the transportation infrastructure) of the user ("Where am I?", e.g., "T1", "R1 between T1 and T2", etc.) and refresh the user interface accordingly.
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.