N°INSEE
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript dans une classe
N_INSEE
un système de saisie contrôlée d'un N°INSEE (ou N°SS) selon la formule suivante :clef = 97 - (N°INSEE % 97)
. On rappelle qu'un N°INSEE est défini sur 13 chiffres (e.g., 1630125388055, clef = 29) et que sa clef est saisie simultanément pour contrôle.En C++, il est nécessaire de vérifier qu'un N°INSEE tient sur le format
long
et dans le cas contraire le remplacer par le 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 (ici… ou là… pour se faire la main en JavaScript/TypeScript).
En JavaScript/TypeScript, pour signifier le résultat à l'utilisateur, utiliser la librairie SweetAlert2. A ce titre, faire apparaître un message différencié selon l'issue du calcul de clef (i.e., OK ou Non OK). Organiser le code en deux fichiers source différents, l'un (
N_INSEE.js
) faisant le calcul et l'autreMain.js
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 JavaScript malgré ce qui est annoncé sur le site Web.Avec Angular, partir de l'implémentation TypeScript précédente pour obtenir le visuel qui suit.
![]()
Faire de même avec React en partant de l'implémentation JavaScript.
Application(s)
Before yesterday, yesterday…
En s'inspirant d'un programme C++ déterminant en fonction du temps machine si une date donnée est « Avant hier », « Hier »…, implanter en Java et/ou Python et/ou JavaScript/TypeScript un programme équivalent.
Pour Java, il y a lieu de mettre en œuvre l'API Date-Time qui a complètement été revue en Java 8 (ici).
// Before_yesterday_.h #ifndef _Before_yesterday_H #define _Before_yesterday_H #include <string> class Before_yesterday_ { public: static const std::string Avant_hier; static const std::string Hier; static const std::string Aujourd_hui; static const std::string Demain; static const std::string Apres_demain; static const std::string Je_n_en_sais_rien; Before_yesterday_(int, int, int, std::string&); }; #endif // Main.cpp #include <cassert> #include <ctime> #include <iostream> #include <string> #include "Before_yesterday_.h" const std::string Before_yesterday_::Avant_hier = "Avant hier"; const std::string Before_yesterday_::Hier = "Hier"; const std::string Before_yesterday_::Aujourd_hui = "Aujourd'hui"; const std::string Before_yesterday_::Demain = "Demain"; const std::string Before_yesterday_::Apres_demain = "Après demain"; const std::string Before_yesterday_::Je_n_en_sais_rien = "Je n'en sais rien"; Before_yesterday_::Before_yesterday_(int jour, int mois, int annee, std::string& resultat) { assert(jour > 0 && mois > 0 && annee > 0); assert(jour <= 31 && mois <= 12); std::time_t maintenant = std::time(&maintenant); // std::cout << std::asctime(std::localtime(&maintenant)) << std::endl; std::tm *maintenant_comme_structure_de_donnes = std::gmtime(&maintenant); // 'auto' permet de déterminer automatiquement le type de 'jour_systeme' en fonction du type (ici 'int') de la donnée affectée : auto jour_systeme = maintenant_comme_structure_de_donnes->tm_mday; auto mois_systeme = maintenant_comme_structure_de_donnes->tm_mon + 1; // Attention : 'tm_mon' retourne le mois système moins '1' ! auto annee_systeme = maintenant_comme_structure_de_donnes->tm_year + 1900; // Attention : 'tm_year' retourne l'année système moins '1900' ! resultat = Je_n_en_sais_rien; if (annee == annee_systeme) { if (mois == mois_systeme) { if (jour == jour_systeme - 2) resultat = Avant_hier; if (jour == jour_systeme - 1) resultat = Hier; if (jour == jour_systeme) resultat = Aujourd_hui; if (jour == jour_systeme + 1) resultat = Demain; if (jour == jour_systeme + 2) resultat = Apres_demain; } } } int main(int argc, char** argv) { std::string resultat; Before_yesterday_ Before_yesterday_(9, 5, 2019, resultat); std::cout << resultat << std::endl; return 0; }
Application(s)
Leap year
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript dans une classeAnnee_bissextile
, deux fonctions booléennes établissant si, oui ou non, une année est bissextile (leap year en anglais). La première fonction prend en paramètre l'année sous forme entière alors que la seconde la prend sous forme d'un type gérant les dates.Pour C++, ce type est
time_t
(#include <ctime>
).Pour Java, ce type peut être
java.util.Calendar
ou mieux, on utilise l'API Date-Time complètement relookée en Java 8 (ici).Les deux exemples qui suivent donnent une méthode de récupération de l'année du temps machine en C++ et Java.
std::time_t now = std::time(&now); // '#include <ctime>' // Display for control: std::cout << std::asctime(std::localtime(&now)) << std::endl; // '#include <iostream>' std::tm *now_as_data_structure = std::gmtime(&now); int year = now_as_data_structure->tm_year; // Caution: 'tm_year' returns the current year minus '1900'!
java.util.Calendar now = java.util.Calendar.getInstance(); int year = now.get(java.util.Calendar.YEAR);
Application(s)
Lotto!
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript dans une classe
Tirage_loto
un calcul permettant de remplir automatiquement une grille de loto simple avec 48 valeurs différentes à choisir entre 1 et 49 inclus. On a en fait 8 jeux consistant à choisir à chaque fois 6 chiffres mais on n'utilise pas les mêmes chiffres entre chaque jeu.Pour gérer des suites de nombres aléatoires, on utilise opportunément :
- C++ : les fonctions
std::srand(unsigned int)
etstd::rand()
(#include <cstdlib>
)- Java : la classe
java.util.Random
ou la fonction prédéfinieMath.random()
- JavaScript/TypeScript : la fonction
Math.random()
Application(s)
Color
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript une classe
RGB_color
sur le modèle Java qui suit. Une couleur RGB est représentée sur 32 bits : 8 bits les plus à gauche pour l'opacité puis 8 bits pour la nuance de rouge, etc.public class RGB_color { // RGB: 8 left-most bits: alpha, then next 8 bits: red, green, blue... public enum Red_shade { // Look at red color named shades in CSS and HTML on the Web... crimson, darkred, tomato // Etc. }; public RGB_color(String css_html_hexadecimal) { // Use a regular expression to check 'css_html_hexadecimal' format, // e.g., "#FFFF0000" for "fully opaque red"... // Construct '_representation' from 'css_html_hexadecimal'... } private java.util.BitSet _representation = new java.util.BitSet(Byte.SIZE * 4); public float alpha() { // '0.F' if totally transparent, '1.F' if totally opaque, between '0.F' and '1.F' otherwise return ...; } public boolean is_color(Red_shade red_shade) { // 'true' if 'red_shade' is color implemented as bit set in '_representation' return ...; } public String css_html_hexadecimal() { String css_html_hexadecimal; // Construct 'css_html_hexadecimal' from '_representation', for example, "fully opaque red": return "#FFFF0000"; } }
Account
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript une classeAccount
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 JavaScript/TypeScript le concept de température sachant qu'une température ne peut pas descendre en dessous du zéro absolu. Cette propriété peut être formalisée via une fonction accessor constante sur le type abstrait de donnéesTemperature
comme suit :La fonction
Min: Temperature → tMin
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 :
t: Temperature, asCelsius(Min(t)) = –273.15
Les deux axiomes suivants s'appliquent :
asCelsius: Temperature → Real
asFahrenheit: Temperature → Real
asKelvin: Temperature → Real
Prévoir des fonctions d'incrémentation et de décrémentation avec un pas « fin » (
t: Temperature, asKelvin(t) = asCelsius(t) - asCelsius(Min(t))
t: Temperature, asFahrenheit(t) = 9/5 * asCelsius(t) + 32.
10
-3
ou moins) matérialisé par une variable d'instance_step
.
Pour Java, créer une classe
*L'outil JavaFX Scene Builder peut être intégré dans à NetBeans pour dessiner l'interface homme-machine.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 une zone de texte. Prévoir aussi une checkbox pour établir dans quelle unité de mesure s'exprime cette température (exprimer avec °C ou °F uniquement).Pour JavaScript/TypeScript, appliquer les mêmes règles que pour Java et créer l'interface homme-machine dans une page Web avec HTML et CSS.
Application(s)
Face detection
Ce travail concerne les tableaux JavaScript (type
Array
: doc. ici…) qui jouent un rôle extrêmement important. Un logiciel de détection de caractéristiques (la face en bleu, la bouche en vert et les yeux en rouge) donne des résultats pléthoriques nécessitant un post-processing.![]()
Le post-processing consiste à appliquer des heuristiques simples comme par exemple le fait que « les yeux se trouvent au-dessus de la bouche » ou encore « la bouche et les yeux sont totalement inclus dans la face » (voir toutefois Macron pour qui cette heuristique est inadaptée). Dans le logiciel de détection,
this._eyes
est une promesse JavaScript qui par la 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.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); });
Application(s)
Horner
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/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 la librairie SweetAlert2 en JavaScript/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 (ici).- Pour JavaScript/TypeScript, on peut opportunément réutiliser la fonction
sort
sur les tableaux pour obtenir cet ordre après la saisie avec SweetAlert2. En l'occurrence, le programmeHorner_method.js
ci-après utilise la variablepolynomial
comme un tableau d'objets, i.e.,polynomial.push({degree: …, coeff: …});
. Réviser ce programme en utilisant un dictionnaire JavaScript/TypeScript Map.Application(s)
Lips
Le but du travail est de manipuler les tableaux en JavaScript (type
Array
: doc. ici). L'application 3D qui suit montre une géométrie de lèvres « brute ». Une géométrie est fondée sur un tableau de sommets (vertices en anglais) et un tableau de faces. 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 par la classe génériquetemplate<class T1,class T2> struct pair
(2-uplet uniquement) et plus généralement la classe génériquetemplate<class... Types> class tuple
en C++.Traduire ce programme en Java et/ou Python et/ou JavaScript/TypeScript en gérant les accents français ainsi que le « ç » voire d'autres caractères « problématiques ».
En JavaScript/TypeScript, utiliser la balise HTML
input
en conjonction avec les événements'input'
(un caractère saisi) et'change'
(tous les caractères saisis). Tenter de détecter au plus tôt avec l'évé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
(ici) ainsi qu'un programme simple manipulant cette classe. La hiérarchie d'héritage proposée s'appuie sur l'héritage multiple de classes en C++. Revoir en Java et/ou Python et/ou JavaScript/TypeScript cette classeCurrency
ainsi que ses descendantes. Construire en suivant les classesDirham_marocain
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
(ici) ainsi qu'un programme simple manipulant cette classe. La hiérarchie d'héritage proposée s'appuie sur l'héritage de classes et l'implémentation d'interfaces en Java. Revoir en C++ et/ou Python et/ou JavaScript/TypeScript cette classeCurrency
ainsi que ses descendantes. Construire en suivant les classesDirham_marocain
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 JavaScript/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 JavaScript/TypeScript en vérifiant si ces langages autorisent de poser de telles contraintes sur l'héritage ?
public class Note { // Fichier 'Note.java' private final static char _Caractere_de_fin = '\n'; private final static String _Entete_par_defaut = "Pour information : "; private final static int _Nombre_d_espaces_par_defaut = 1; private final String[] _source; protected String _texte; public Note(String[] source, String entete) { _source = source; initialization(entete); } protected void initialization(String entete) { if (entete != null) { _texte = entete; } else { _texte = _Entete_par_defaut; } } public String construire() { for (String s : _source) { _texte += s; for (int i = 0; i < _Nombre_d_espaces_par_defaut; i++) { _texte += ' '; } } _texte += _Caractere_de_fin; return _texte; } } … public class Confidential_note extends Note { // Fichier 'Confidential_note.java' private final static String _Entete_par_defaut = "Pour information (confidentiel) : "; public Confidential_note(String[] source, String entete) { super(source, entete); } protected void initialization(String entete) { // On est obligé de redéfinir la fonction 'initialization' car '_Entete_par_defaut' est différent... if (entete != null) { super.initialization(entete); } else { _texte = _Entete_par_defaut; } } }
Application(s)
Légumes
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, donnez le code sous forme de graphe d’héritage en C++ et/ou Java et/ou JavaScript et/ou Python à partir de la classe suivante :
class Legume { public: virtual Legume* graine() const = 0; // Retourne un clone du légume en question, i.e., un clone de 'this'... };
abstract public class Legume { abstract public Legume graine(); // Retourne un clone du légume en question, i.e., un clone de 'this'... }
class Legume { // On simule avec 'return undefined;' le fait que 'graine' est une méthode abstraite, i.e., // on aurait utilisé le mot-clef 'abstract' en Java mais il n'existe pas en JavaScript : graine() { return undefined; } // Retourne un clone du légume en question, i.e., un clone de 'this'... }
C++ : donnez 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 : remplacer après la classe
Legume
par une interface et donnez le lien entre l'interfaceLegume
et le type « légumes-feuilles ».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)
Quick sort
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript le tri lent et le tri rapide (quick sort en anglais)
En C++, faire des mesures de temps calcul grâce aux types
time_t
ettm
(#include <ctime>
) de la bibliothèque standard outimeb
(#include <sys/timeb.h>
) de la bibliothèque « système » (localisation avecmore < /usr/include/sys/timeb.h
sous UNIX).Faire de même en Java sans mesure de temps calcul puis, dans un second temps, réutiliser la classe Java
java.util.Collections
et ses méthodessort
.Faire de même en Python sans mesure de temps calcul puis, dans un second temps, réutiliser la classe Python
list
et sa fonctionsort
.Faire de même en JavaScript/TypeScript sans mesure de temps calcul puis, dans un second temps, réutiliser la classe JavaScript
Array
et sa fonctionsort
.Pour remplir les tableaux à trier en gagnant du temps, on peut opportunément utiliser :
- C++ : les fonctions
std::srand(unsigned int)
etstd::rand()
(#include <cstdlib>
)- Java : la classe
java.util.Random
ou la fonction prédéfinieMath.random()
- JavaScript/TypeScript : la fonction
Math.random()
Application(s)
Fibonacci
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript la suite de Fibonacci sur la base de trois méthodes de calcul : méthode récursive, méthode itérative ou formule de Binet.
Faire des mesures de temps calcul (cf. Quick sort) et expliquer les performances inhérentes aux trois méthodes lorsque les nombres en entrée deviennent « grands ».
Application(s)
Euclid
Implanter en C++ et/ou Java et/ou Python et/ou JavaScript/TypeScript l'algorithme d'Euclide.
Introduire une variable « artificielle » mesurant le coût du calcul récursif (i.e., incrémenter le coût de
1
à chaque appel récursif). Vérifier empiriquement que ce coût est proche delog(b)
si on calculeeuclid(a,b)
.Application(s)
RSA algorithm
L'algorithme RSA est un algorithme de cryptage basé sur des mathématiques (fichier PDF ici…). Faire une implémentation en Java de cet algorithme en tirant parti de la classejava.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.
En JavaScript/TypeScript, utiliser l'API
fetch
(ici…) pour interroger un site Web. Prévoir une interface homme-machine HTML-CSS permettant de faire les conversions avec, notamment, le Dirham marocain et le Bitcoin.En Java, interroger un site Web et traiter des données JSON est expliqué ici. Utiliser l'API native de Java ou, par exemple, la bibliothèque OkHttp. Prévoir une interface homme-machine permettant de faire les conversions en choisissant l'une ou l'autre des modalités suivantes :
- Utiliser JavaFX,
- Ou communiquer les données Java à JavaScript/TypeScript grâce à la technologie WebSockets (des archétypes de collaboration sont expliqués et disponibles ici…). Prévoir une interface homme-machine HTML-CSS permettant de faire les conversions avec, notamment, le Dirham marocain et le Bitcoin.
Application(s)
Image processing
Le but du travail est de s'intéresser aux objets JavaScript de type
HTMLCanvasElement
(spec. ici). On peut aisément créer dynamiquement un canvas.let canvas = window.document.createElement('canvas'); canvas.id = "My canvas"; canvas.width = 1200; canvas.height = 800; canvas.style.zIndex = 10; canvas.style.position = "absolute"; canvas.style.border = "1px solid"; window.document.body.appendChild(canvas);
Un canvas offre des fonctions de dessin et/ou il est rempli via une image. Dans le second cas, il est alors intéressant de pouvoir faire des traitements d'image (illustration ici) via l'accès aux pixels du canvas. Toutefois, ces traitements peuvent être couteux en temps machine d'où la nécessité de travailler directement avec des background buffers qui sont formatés spécialement pour des accélérations GPU (illustration ici).
Voici un exemple de traitement d'image de manière à reconstruire cette image dans un monde 3D.
En s'aidant de la bibliothèque logicielle dat.GUI, le travail consiste à construire une page Web dans laquelle on charge une image puis on opère des changements comme ceux proposés ici. On rappelle qu'il faut manipuler les pixels avec les background buffers.
Application(s)
Drag & Drop
Le but du travail est de s'intéresser aux événements JavaScript clavier, souris ainsi qu'aux événements Drag & Drop. Considérant l'application JavaScript en fonctionnement ci-dessous, on souhaite faire évoluer son fonctionnement comme suit :
- On veut pouvoir à tout moment annuler le compte à rebours en cours avec la souris puis on saisit une donnée définissant une nouvelle valeur de compte à rebours ; on redémarre le compte à rebours.
- Avec la souris toujours, on veut pouvoir effectuer une pause du compte à rebours en cours ; on le reprend à la demande.
- On veut pouvoir à tout moment changer l'image (la texture en fait) de l'objet 3D injecté via un Drag & Drop. Attention, le Drag & Drop est ici un glisser-lâcher d'un fichier image provenant du système d'exploitation. Par défaut, un browser affiche cette image. Ce comportement par défaut doit donc être redéfini.
Mise à jour de la texture :
new THREE.TextureLoader().load(/* URL du fichier récupéré via 'FileReader' */, function(texture) { let bus = this._scene.getObjectByName(this._image_URL); bus.material.map = texture; bus.material.needsUpdate = true; }.bind(this));
Application(s)
Jeu de découverte de personnage
Le but du jeu est de trouver le nom d'un personnage dans un temps limité. S'affichent le temps restant en millisecondes ainsi qu'une zone de saisie permettant de répondre.
![]()
Les données du jeu peuvent être organisées comme suit :
export default class Game { static Data = new Array( { Answer: /O[b]+a[m]+a/i, // ObbamMa URLs: [ "./img/Obama-1.jpg", "./img/Obama-2.jpg"], Time: 10000 }, { Answer: /Tr[ou]+mpe?/i, // 'Trompe' accepté ! URLs: [ "./img/Trump-1.jpg", "./img/Trump-2.jpg"], Time: 10000 } // Etc. ); … }
L'idée est de transformer la réponse du joueur en promesse à partir de l'événement
'change'
de la baliseinput
:const reponse_complete = new Promise(resultat => { window.document.getElementById("reponse").addEventListener('change', (event) => { // L'événement 'change' est produit par JavaScript lorsque l'utilisateur a tapé "Return"... if (Game.Data[personnage].Answer.test(event.target.value)) resultat("gagné"); else resultat("perdu"); }); });
Il faut faire de même avec le timer ainsi que l'événement
'input'
de la même baliseinput
. Au final, est affiché « gagné » ou « perdu » sur l'image selon que la réponse est correcte ou que le timer « claque ».Application(s)
Statecharts
L'application My device est une application JavaFX pour la partie interface homme-machine. Le cœur de l'application est un automate de type Statecharts de Harel. L'exécution de cet automate est basé sur la bibliothèque Java PauWare. L'équivalent de PauWare en JavaScript est SCION-CORE. L'application My device, bien qu'elle puisse s'exécuter dans un browser, pose des contraintes de sécurité qu'il est de plus en plus difficile de satisfaire en regard de l'évolution des browser du marché (Firefox, Chrome, Safari, etc.).
Le travail consiste ainsi à concevoir l'interface homme-machine en HTML, CSS et JavaScript/TypeScript ainsi que réécrire le cœur de l'application avec le « moteur d'exécution » SCION-CORE sous les considérations suivantes :
- 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.
Le programme Node.js de Web scraping qui suit récupère sommairement des images via le moteur de recherche Google dédié : images.google.com. Toutefois, l'« aspiration » de données sur le Web est souvent considérée comme une forme de vol d'où une sécurisation à tout-va, exemple : société DataDome. Le groupe Carrefour par exemple protège ses données via la technologie de cette société. Typiquement la requête https://www.carrefour.fr/s?q=3560070478781, bien qu'elle puisse s'exécuter via un browser (Firefox, Chrome, Safari, etc.), est plus difficile à exécuter par un « bot » qui souhaite aspirer photos, prix… voire qualités nutritionnelles, composition (produits alimentaires uniquement)… associés à un produit connu par son code barre ou GTIN (Global Trade Item Number).
En opposition à ce mouvement de sécurisation à tout-va, notre ami El Pueblo souhaite disposer d'une application capable, sur la base d'une liste de produits bien déterminés, lui dire si Carrefour Lescar, Leclerc Pau Université, Géant Casino Lons… lui garantit le prix le plus bas pour sa liste. Si une telle application aujourd'hui existe (?), elle masque peut-être le fait que les données qu'elle utilise sont payées ; en d'autres termes, des groupes comme Carrefour cherchent à (aussi) devenir des entreprises « digitales ».
Le travail consiste ainsi à adapter le programme Node.js qui suit pour tenter d'aspirer les photos des produits Carrefour. Méthode :
- 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. Où sont les liens vers les (URLs des) images ?
- Via l'utilisation d'expressions régulières (ici…), délimiter les URLs des images puis sauver alors les images localement sur disque. Indication :
- Exemple 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\\\/)+/
/* Node.js program */ const fs = require('fs'); // 'npm i @types/node' let us access to 'require', etc. // 'puppeteer.js' library: https://developers.google.com/web/tools/puppeteer/ const puppeteer = require('puppeteer'); // 'npm install --save puppeteer' or 'sudo npm install --save puppeteer' // Recent download problems require this: 'sudo npm install puppeteer --unsafe-perm=true --allow-root' // 'request.js' library: https://www.npmjs.com/package/request const request = require('request'); // 'npm install --save request' or 'sudo npm install --save request' // Check whether 'puppeteer.js' and 'request.js' have been properly installed: 'npm list -depth=0' class Google_Images { private static readonly _Database: string = './Database/'; private static readonly _Path: string = '/search?tbm=isch&q='; private static readonly _URL: string = 'https://www.google.com'; static async Take_picture() { // Returned type is inferred from 'async', i.e., 'Promise' const browser = await puppeteer.launch({headless: true}); // Launch 'Chrome' *WITHOUT* visual environment // Following call *DOES NOT* occur (because of prior 'await') until prior one terminates: const page = await browser.newPage(); await page.goto(Google_Images._URL + Google_Images._Path + (typeof process.argv[2] === 'string' ? process.argv[2] : '')); // By default, 'page.goto(...)' waits for the page load event const photo_file_name: String = (typeof process.argv[2] === 'string' ? process.argv[2] : 'undefined') + '.png'; let body: String = await page.evaluate(() => document.body.innerHTML); const start_index: number = body.search("https://encrypted-tbn0.gstatic.com"); if (start_index !== -1) { let image_URL: String = body.substring(start_index); image_URL = image_URL.substring(0, image_URL.search("\"")); request(image_URL).pipe(fs.createWriteStream(Google_Images._Database + photo_file_name)); } else await page.screenshot({path: Google_Images._Database + photo_file_name}); // Default picture... await browser.close(); return photo_file_name; } } Google_Images.Take_picture().then((photo_file_name) => { console.log('Photo file name: ' + photo_file_name); });
Application(s)
Crisis management
L'application Java BCMS est un système de gestion de crise impliquant policiers et pompiers qui de façon coopérative procèdent à une intervention sur le lieu d'une crise « en cours ». Le processus de gestion de crise consiste à décider de l'envoi de voitures et de camions dont policiers et pompiers suivent l'envoi et l'arrivée jusqu'à ce que la crise soit terminée. En l'état, l'application n'a pas d'interface homme-machine. Plus précisément, un programme Java
main
teste l'enchaînement de deux crises pour vérifier grossièrement que l'application globalement fonctionne.Le travail consiste à fabriquer une interface homme-machine en JavaFX ou en HTML, CSS et JavaScript/TypeScript. Dans le second cas, il faut utiliser la technologie WebSockets pour pousser les données à afficher de Java au browser ; les consignes arrivent alors elles en sens inverse (des exemples de programmes WebSockets sont expliqués et disponibles ici…). Cette interface homme-machine doit permettre de se connecter en tant que policier (Police Station Coordinator) ou en tant que pompier (Fire Station Coordinator). Une fois connecté en tant que policier, seules les fonctionnalités associées au rôle de policier dans l'application sont disponibles et donc activables via l'interface homme-machine (idem pour la « connexion pompier »). Par exemple, l'instruction Java
bCMS.state_fire_truck_number(2);
du programme de test actuel ne doit être accessible qu'à la « connexion pompier ».Artificial Intelligence (AI)
xxx.
yyy.
Application(s)
Computer Integrated Manufacturing (CIM)
Une application Node.js (cahier des charges ici… et implémentation là…) écrite en TypeScript et basée sur les “frameworks” Express et @Hapi/Joi est un embryon d'architecture micro-services permettant de créer des « articles » de type « produit fini », « matière première », « pièce » et « sous-ensemble ». Au service Web de création d'article (
POST
), s'ajoutent deux services Web de lecture, d'un article sur sa « référence » et de tous les articles (GET
).Le travail consiste à 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
).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 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” (voir aussi ici…) qu'il est possible d'interroger.package com.FranckBarbier.Java.JNDI_DNS; import javax.naming.*; import javax.naming.directory.*; public class JNDI_DNS { public JNDI_DNS() { try { java.util.Properties _p = new java.util.Properties(); // For Java 9 and more: https://mvnrepository.com/artifact/com.sun.jndi/dns: _p.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); // Use another DNS server (platform config. otherwise: https://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-dns.html#URL): // _p.setProperty(Context.PROVIDER_URL, "dns://194.167.156.13"); // UPPA // _p.setProperty(Context.PROVIDER_URL, "dns://8.8.8.8"); // Google // _p.setProperty(Context.PROVIDER_URL, "dns://193.146.78.14"); // University of Mondragon DirContext dc = new InitialDirContext(_p); Attributes attributes = dc.getAttributes("FranckBarbier.com", new String[]{"NS"}); // Stores the name server for a DNS entry... if (attributes != null) { NamingEnumeration ne = attributes.get("NS").getAll(); while (ne.hasMoreElements()) { System.out.println("[NS] entry: " + ne.next().toString()); } } // Get all Web address suffixes: InitialContext _ic = new InitialContext(_p); System.out.println("\nInitial context: " + _ic.getNameInNamespace()); NamingEnumeration ne = _ic.list(""); while (ne.hasMore()) { System.out.println("\t" + ((NameClassPair) (ne.next())).getName()); } NameParser np = _ic.getNameParser(_ic.getNameInNamespace()); Name university_of_Mondragon = np.parse("www.mondragon.edu"); System.out.print("\nwww.mondragon.edu has " + university_of_Mondragon.size() + " components:"); for (int i = 0; i < university_of_Mondragon.size(); i++) { System.out.print("\t" + university_of_Mondragon.get(i)); } Object o = _ic.lookup(university_of_Mondragon.getPrefix(university_of_Mondragon.size() - 1)); ne = (((com.sun.jndi.dns.DnsContext) o).getAttributes(university_of_Mondragon, null)).getAll(); while (ne.hasMore()) { BasicAttribute ba = (BasicAttribute) ne.next(); System.out.print("\n\tAttribute id. [" + ba.getID() + "]: "); NamingEnumeration nee = ba.getAll(); while (nee.hasMore()) { System.out.print("\t" + nee.next()); } } System.out.println("\n\nClosing..."); _ic.close(); } catch (NamingException ne) { System.err.println(ne.getMessage() + ": " + ne.getExplanation()); } } public static void main(String[] args) { new JNDI_DNS(); } }
Le but du travail est d'utiliser la technologie JNDI comme une technologie « serveur » dans le cadre d'une application Web de type “WHOIS”. Via une interface homme-machine HTML/CSS à imaginer, l'utilisateur peut obtenir tout type d'informations via un nom de domaine saisi par lui.
Pour communiquer les données trouvées par Java (après exécution de requêtes JNDI) à JavaScript, la technologie WebSockets (des archétypes de collaboration sont expliqués et disponibles ici…) est mise en œuvre. De même, JavaScript envoie à Java les ordres de recherche en format JSON (traiter des données JSON avec Java est expliqué ici…).
Application(s)
Enterprise JavaBeans™ (EJB) 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. Banking_system.Derby.sql
is the JavaDB database SQL script
.
The proposed work consists in extending this application so that it supports CRUD (-Create, Read, Update, Delete-) functions for the
Logical_card
table in the database (please keep the database schema “as is”).Enterprise JavaBeans™ (EJB), “local” versus “remote” interface
Given
Asterix
andObelix
as two collaborative Session Beans.Asterix
has a business method namedstrength
, which itself calls a business method offered byObelix
also namedstrength
.
- Implement
Asterix
andObelix
in the same EJB module as follows:
- Both are Stateless Session Beans (use the following annotation value for
Obelix
:mappedName = "ejb/Obelix"
)- Dependency injection in
Asterix
toObelix
as follows:@javax.ejb.EJB(mappedName = "ejb/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
.NetBeans tutorial
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épondez 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épondez 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épondez 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épondez 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.
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 :
Pour pallier le problème, on « capture » les composants différemment (ce code s'ajoute au code préalable) :// '@javax.ejb.EJB' est mise en commentaires car ne fonctionne pas... private java.util.Collection<My_stateless_remote> _collection_of_My_stateless_remote;
Bien que ce code fonctionne, quelle est une meilleure alternative ?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épondez aux questions figurant dans ce document en fonction de l'application EJB Premiers.EJB.zip
.
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 software engineer. 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.Enterprise JavaBeans™ (EJB) with JavaServer Faces (JSF) bis repetita
Being inspired by the New York City Penitentiary (NYCP) case study that is based on EJB and JSF, implement a CRUD (Create, Read, Update, Delete) application for a (requirements doc. in French) Computer-Integrated Manufacturing case study.