PROGRAMMAZIONE DISTRIBUITA
Università degli Studi di Salerno
Libri di testo
Materiale
🗓️ | Lezione | Materiale | Riferimenti |
---|---|---|---|
23/09/2024 | Presentazione Corso + Introduzione Programmazione Distribuita (Prof. Scarano) | 📕 Cap. 1 | |
26/09/2024 | Programmazione Distribuita (Prof. Scarano) 1 | 📕 Cap. 1 | |
27/09/2024 | Programmazione Distribuita (Prof. Scarano) 2 | 📕 Cap. 1 | |
30/09/2024 (pari-dispari) | Java Thread 1 | 📋 Official Java Essential Concurrency 🌐 Insights: O'Reilly Java Threads (google it) | |
03/10/2024 | Java Thread 2 | 💾 Alphonse and Gaston Java Thread ⚙️ Installazione ambiente di sviluppo (solo prima sezione) | 📋 Official Java Essential Concurrency |
04/10/2024 | Laboratorio Thread | Esercitazione Java Thread | Official Java Essential Concurrency |
07/10/2024 (dispari-pari) | Java Socket TCP 1-2 | 📋 Official Java All About Sockets | 📕Cap. 2 |
10/10/2024 | RMI 1 | 📕 Cap. 3 | |
11/10/2024 | RMI 2 | RMI 1 - Hello World | 📕 Cap. 4 |
14/10/2024 (pari-dispari) | Laboratorio Java RMI | RMI - Esercizi Java RMI | |
Fine Parte A | |||
17/10/2024 | Introduzione Java Enterprise Edition (Java EE) | Java EE | 📗 Cap. 1 |
18/10/2024 | Contexts and Dependency Injection (CDI) | CDI Part 1 | 📗 Cap. 2 |
21/10/2024 | Laboratorio Starting with J2EE | J2EE Lab | |
24/10/2024 | CDI Interceptor ➕ Laboratorio J2EE | CDI Part 2 | 📗 Cap. 2 |
25/10/2024 | Java Persistence API (JPA) | JPA - Part 1 | 📗 Cap. 4-5 |
28/10/2024 | Java Persistence API (JPA) | JPA - Part 2 Laboratorio JPA | 📗 Cap. 4-5 |
31/10/2024 | Enterprise JavaBeans (EJB) - Part 1 ➕ Laboratorio EJB (Esercizio 0) | EJB - Part 1 | 📗 Cap. 7-9 |
04/11/2024 | EJB - Part 2 ➕ Laboratorio EJB | EJB - Part 2 EJB - Lab | 📗 Cap. 7-9 |
07/11/2024 | Java Message Service (JMS) - Part 1 | JMS - Part 1 | 📗 Cap. 13 |
08/11/2024 | JMS - Part 2 | JMS - Part 2 | 📗 Cap. 13 |
11/11/2024 | Laboratorio EJB ➕ 📝 Quiz Parte A | 📕 | |
14/11/2024 | Laboratorio EJB ➕ JMS | EJB - Lab JMS - Lab | |
Fine Parte B | |||
15/11/2024 | Laboratorio EJB ➕ JMS | EJB - Lab JMS - Lab | |
18/11/2024 | Java Web Services (WS) | Java Web Services (WS) Parte 1 | 📗 Cap. 14 |
21/11/2024 | Laboratorio Java WS ➕ Laboratorio J2EE Step-by-step | Laboratorio Java WS | |
22/11/2024 | Introduzione al Cloud Computing | Materiale cloud computing | |
25/11/2024 | Laboratorio J2EE Step-by-step ➕ 📝 Quiz Parte B | ||
28/11/2024 | From J2EE to Spring Framework (Teoria) | Introduzione a Spring Framework | |
29/11/2024 | From J2EE to Spring Framework (Pratica) | Spring Framework In Action | |
02/12/2024 | Laboratorio J2EE Simulazione | ||
05/12/2024 | Laboratorio J2EE Simulazione | ||
06/12/2024 | 📝 Prova Parte C | ||
09/12/2024 | Cloud Computing 2 |
Informazioni modalità d'esame
Prova scritta ➡️ Svolgimento prova a casa ➡️ Consegna progetto ➡️ Prova orale
Prova scritta
Date (da verificare su ESSE3)
🗓️ | 🕘 | 📍 |
---|---|---|
17/01/2025 | 09:00-12:00 | P3/P4 |
07/02/2025 | 09:00-12:00 | P3/P4 |
21/02/2025 | 09:00-12:00 | P3 |
Note sullo svolgimento della prova scritta
- Alla terminazione della prova scritta dovete scansionare il compito per poterlo svolgere a casa.
- Ricordatevi di portare un congruo numero di fogli bianchi e almeno due penne. La commissione non vi consegnerà NULLA e voi non potrete assolutamente scambiarvi oggetti.
- Il cellulare dovrete averlo con voi (Modalità aereo), non potrete alzarvi per recuperarlo dagli zaini.
- Sul vostro cellulare dovrà essere già installata una qualunque app per la scansione del compito.
- A compito terminato dovrete effettuarne la scansione usando il vostro cellulare. Dovrete a questo punto comunicare alla commissione di voler eseguire la scansione e successivamente procedere alla scansione senza muovervi dal vostro posto.
Suggerimenti utili
- Scrivete in maniera chiara, senza troppe cancellature, seguite l’ordine di progettazione indicato nella traccia e indentate correttamente il codice.
- Rispondere alla domanda di teoria in maniera chiara, puntuale e precisa, eventuali argomenti non chiesti non verranno valutati.
- Parti non implementate durante l’esame non dovranno essere consegnate nel progetto import, getter, setter e toString si possono omettere nello scritto, ma i costruttori vanno implementati.
➡️ Svolgimento prova a casa
-
I progetti da consegnare (progetti NetBeans) si devono chiamare “COGNOMENOMEXXX” nei rispettivi files COGNOMENOMEXXX.zip (devono essere esportati).
-
L’archivio che li contiene TUTTI insieme deve chiamarsi COGNOMENOME_EE.zip
-
Deve esserci un UNICO file readme.txt (non Readme, non leggimi, …) all’interno di COGNOMENOME_EE.zip che illustri le modifiche che si sono rese necessarie (per ogni file di ogni progetto) rispetto a quanto consegnato, secondo lo schema presente alla fine di questo documento.
-
Le modifiche devono essere commentate ANCHE nel codice dei progetti.
Esempio file readme.txt
Cognome e Nome: XXXXXXX Data: gg/mm/yy Breve descrizione riassuntiva delle modifiche: xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx ------------------------------ MODIFICHE PROGETTO: NOMEPROGETTO 1 FILE: xxxxxx Linea 4: xxxxxxxxxx Linea 34: xxxxxxxxxx Linea 52: xxxxxxxxxx FILE: yyyy Linea 7: xxxxxxxxxx Linea 13: xxxxxxxxxx Linea 22: xxxxxxxxxx PROGETTO: NOMEPROGETTO 2 FILE: xxxxxx Linea 4: xxxxxxxxxx Linea 34: xxxxxxxxxx Linea 52: xxxxxxxxxx FILE: yyyy Linea 7: xxxxxxxxxx Linea 13: xxxxxxxxxx Linea 22: xxxxxxxxxx ...
➡️ Consegna progetto
- I progetti funzionanti, entro la data indicata sul compito, vanno inviati tramite il link che troverete sul compito o sulla piattaforma MS Teams.
- ⚠️ L’invio dei progetti entro la data stabilita è da considerarsi come richiesta di correzione (nel senso che se non viene inviato, il compito non viene corretto!).
➡️ Prova orale
- Il calendario delle prove orali (per gli ammessi) sarà comunicato su MS Teams per ogni appello.
Blog
-
Test RMI Thread Safeness ✅: importare i sorgenti in un nuovo progetto Java Application. Eseguire prima l'ogetto remoto
MessengerServiceImpl
e poi il fileClient
che esegue 50 clients in thread separati. -
Netbeans shortcuts and Java editor code template: provare a digitare
psvm
oppuresout
+ Tab. - Z. Yu, C. Bai, L. Seinturier and M. Monperrus, "Characterizing the Usage, Evolution and Impact of Java Annotations in Practice," in IEEE Transactions on Software Engineering, vol. 47, no. 5, pp. 969-986, 1 May 2021, doi: 10.1109/TSE.2019.2910516
- Modern Java EE Design Patterns - Building Scalable Architecture for Sustainable Enterprise Development 📖
- Modernizing Enterprise java 📖
- Pro NetBeans™ IDE 6 Rich Client Platform Edition
- The 2022 Java Developer RoadMap
📝 Esame: modalità con prove intercorso per studenti corsisti
A.A. 2024/2025
L'esame per gli studenti corsisti può essere sostenuto tramite 3 prove + prova orale nella data del preappello:
- Quiz Parte A: Fondamenti di programmazione distribuita fino a Java RMI (Libro 📕) 20% del voto di accesso all'esame orale
- Quiz Parte B: Java Enterprise Edition (Libro 📗) 20% del voto di accesso all'esame orale
- Programma JEE Parte C: Sviluppo di un programma in JEE 60% del voto di accesso all'esame orale
Esempi di votazione
20% Quiz Parte A | 20% Quiz Parte B | 60% Programma JEE | Voto di accesso esame orale |
---|---|---|---|
18 | 18 | 18 | 18 |
18 | 30 | 18 | 20,4 |
18 | 18 | 30 | 25,2 |
0 | 0 | 30 | 18 |
30 | 30 | 0 | 12 |
0 | 30 | 30 | 24 |
30 | 0 | 0 | 6 |
Calendario delle prove (da confermare)
Il candidato deve munirsi di un laptop, dotato di Safe Exam Browser, per lo svolgimento della prova tramite la piattaforma di e-learning del dipartimento di informatica.
🗓️ | 🕘 | 📍 | ✅❌ |
---|---|---|---|
Quiz Parte A (Fino a RMI) | 11/11/2023 14:35-17:30 | Lab Sammet | ✅ |
Quiz Parte B (Fino a JMS) | TODO | TODO | ✅ |
Programma JEE | TODO | TODO |
Data di consegna della prova TODO entro le ore 9:00 tramite la piattaforma e-learning di unisa.
Analisi dei risultati 2024-25
Quiz A
Quiz B
A.A. 2023/2024
Calendario delle prove (da confermare)
Il candidato deve munirsi di un laptop, dotato di Safe Exam Browser, per lo svolgimento della prova tramite la piattaforma di e-learning di UNISA.
🗓️ | 🕘 | 📍 | ✅❌ |
---|---|---|---|
Quiz Parte A (Fino a RMI) | 09/11/2023 11:15-11:45 | F8 | ✅ |
Quiz Parte B (Fino a JMS) | 20/11/2023 14:45-15:15 | Lab Sammet | ✅ |
Programma JEE | 18/12/2023 14:30-17:00 | Lab Sammet |
Data di consegna della prova 18/12/2023 entro le ore 9:00 tramite la piattaforma e-learning di unisa.
Analisi dei risultati 2023
Quiz Parte A
Quiz Parte B
Java Thread
Esercizio 1
Scrivere un programma che incrementa un contatore intero per 40000 volte creando una classe Counter e una classe Incrementatore con il main che istanzia e usa Counter (e verificando poi il valore di Counter stampandolo)
- senza thread;
- generando 4 thread che tutti insieme incrementano di 10000 volte il contatore, SENZA curarsi della race condition (e vedere il risultato);
- generando 4 thread, curandosi della race condition (e vedere il risultato!).
Esercizio 2
Scrivere un programma Java per:
- Inizializzare un array di 1200000 interi al valore 42;
- Misurando il tempo necessario.
Verificare le prestazioni del programma al variare del numero dei thread 1 ... P (P> maggiore del numero di thread del processore).
Esercizio 3
Scrivere un programma Java per:
- Sommare un array di 1200000 interi inizializzato con valori pseudo-casuali;
- Misurando il tempo necessario.
Verificare le prestazioni del programma al variare del numero dei thread 1 ... P (P> maggiore del numero di thread del processore).
Esercizio 4
Scrivere un programma Java per:
- Calcolare il massimo di array di 1200000 interi inizializzato con valori pseudo-casuali;
- Misurando il tempo necessario.
Verificare le prestazioni del programma al variare del numero dei thread 1 ... P (P> maggiore del numero di thread del processore).
Esercizio 5
Modificare il seguente codice al fine di scrivere su standard output la stringa smiley :-)
.
public class Smiley extends Thread {
public void run() {
while(true) {
try {
//L TUO CODICE VA QUI
} catch (InterruptedException e)
{ e.printStackTrace(); }
}
}
private void printparentesichiusa() throws InterruptedException {
System.out.println(")"); Thread.sleep(100);
}
private void printtrattino() throws InterruptedException {
System.out.print("-"); Thread.sleep(100);
}
private void printduepunti() throws InterruptedException {
System.out.print(":"); Thread.sleep(100);
}
public static void main(String[] args) {
new Smiley().start();
new Smiley().start();
}
}
Esercizio 6
- Scrivere un programma con 2 thread, che va sempre in deadlock.
- Scrivere un programma con 3 thread, che va sempre in deadlock.
- Scrivere un programma dove un numero n (alto) di thread fa incremento di un contatore (inizializzato a 0) per un numero m (alto) di volte.
- Quando l’incremento del contatore non è in mutua esclusione, causare un errore (alla fine il contatore NON è m*n).
- Inserire tecniche di mutua esclusione di tipo vario e verificare l’impatto sulle prestazioni.
Java Remote Method Invocation (RMI)
Hello World con Java Remote Method Invocation
- In questo esempio utilizzeremo per il servizio di naming Java RMI registry
rmiregistry
presente nella directorybin
della jdk,- per permettere al registro di caricare la codebase necessaria dobbiamo avviarlo all'interno della directory contente i file
.class
del nostro progetto, nel costro caso la direcory$Project/build/classes
- per permettere al registro di caricare la codebase necessaria dobbiamo avviarlo all'interno della directory contente i file
- Per i nostri scopi definiamo un nuovo SecurityManager che garantisce una politica
AllPermission
. - Per la lookup degli oggetti remoti utilizzeremo la classe
Naming
. - Material di supporto: Oracle Getting Started Using Java RMI
- Definizione interfaccia remota
Hello.java
public interface Hello extends java.rmi.Remote {
String dimmiQualcosa(String daChi) throws java.rmi.RemoteException;
}
- Implementazione dell'oggetto remoto
HelloImpl.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.security.Permission;
import java.util.logging.Logger;
public class HelloImpl extends UnicastRemoteObject implements Hello {
private static final long serialVersionUID = -4469091140865645865L;
static Logger logger= Logger.getLogger("global");
public HelloImpl() throws RemoteException { }
public String dimmiQualcosa(String daChi) throws RemoteException {
logger.info("Sto salutando "+daChi);
return "Ciao "+daChi+"!";
}
public static void main(String args[]) throws RemoteException {
//questo codice permette di evitare di scrivere il file policy
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPermission(Permission perm) {
}
@Override
public void checkPermission(Permission perm, Object context) {
}
});
try {
logger.info("Creo l’oggetto remoto...");
HelloImpl obj = new HelloImpl();
logger.info("... ne effettuo il rebind...");
Naming.rebind("HelloServer", obj);
logger.info("... Pronto!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
- Definizione del client che utilizza l'oggetto remoto
HelloClient.java
import java.rmi.*;
import java.util.logging.Logger;
public class HelloClient {
static Logger logger= Logger.getLogger("global");
public static void main(String args[]) {
try {
logger.info("Sto cercando l’oggetto remoto...");
Hello obj = (Hello) Naming.lookup("rmi://localhost/HelloServer");
logger.info("... Trovato! Invoco metodo...");
String risultato = obj.dimmiQualcosa("Pippo");
System.out.println("Ricevuto:"+ risultato); }
catch (Exception e) { e.printStackTrace(); }
}
}
- Esecuzione del progetto
- avviare
rmiregistry
dalla directory~/$PROJECT_NAME/build/classes
porta di defaultrmiregistry
1099. - eseguire
HelloImpl.java
da netbeans tasto destro run file. - eseguire
HelloClient.java
da netbeans tasto destro run file.
- avviare
rmiregistry
locale e export di oggetti remoti
- Server
public void createStubAndBind() throws RemoteException {
MessengerService stub = (MessengerService) UnicastRemoteObject.exportObject((MessengerService) this, 0);
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("MessengerService", stub);
}
- Client
Registry registry = LocateRegistry.getRegistry();
MessengerService server = (MessengerService) registry.lookup("MessengerService");
responseMessage = server.sendMessage("Client Message");
Esercizi Java RMI
- Progettare e realizzare una semplice applicazione RMI client/server per realizzare una calcolatrice:
- Interfaccia remota
Calculator
che definire i metodi per le operazioni di somma, sottrazione, divisione e moltiplicazione; CalculatorImpl
implementa l'interfacciaCalculator
ed estendejava.rmi.server.UnicastRemoteObject
definendo la logica dell'applicazione;CalculatorServer
definisce solo il metodo main e costruisce ed esporta l'oggetto remotoCalculatorImpl
;CalculatorClient
utilizza l'oggetto remotoCalculator
.
- Interfaccia remota
- Progettare e realizzare una applicazione RMI client/server per la gestione delle prenotazioni di un Hotel, con le seguenti operazioni:
- il client deve essere in grado di ottenere la lista delle stanze libere;
- il client può tentare di prenotare una stanza e ottiene un risultato booleano;
- la applicazione deve funzionare in presenza di più client connessi.
- Progettare e realizzare una applicazione RMI client/server per la gestione di un sistema di votazione, con le seguenti operazioni:
- il client deve essere in grado di ottenere la lista dei candidati;
- il client può votare per un candidato e ottiene lo score medio;
- il client può ottenere il risultato delle votazioni (media delle votazioni);
- la applicazione deve funzionare in presenza di più client connessi.
- Progettare e realizzare una applicazione RMI client/server (multi-client) per la gestione di una libreria musicale:
- il client deve essere in grado di ottenere la lista delle canzoni (titolo univoco - link youtube - client name univoco);
- il client può caricare una nuova canzone (titolo univoco - link youtube - client name univoco) visibile a tutti gli altri client;
- il client deve essere in grado di creare delle playlist musicali (sub-set delle canzoni) con titolo univoco visibile a tutti gli altri client;
- il client può eseguire il play di una canzone o di una playlist (il risultato del metodo sono tutti i link youtube);
- il server tiene traccia della riproduzione di una specifica canzone o di una playlist (titolo univoco canzone/playlist, #volte, Lista delle riproduzioni con data e ora);
- il server deve permettere al client di ottenere la lista delle TOP 10 canzoni/playlist riprodotte per ultima settimana, mese e anno.
- Nota 🔗 : ottenere i link da youtube utilizzando il tasto Condividi ➡️ Incorpora dal player youtube;
Java Remote Method Invocation (RMI)
Hello World con Java Remote Method Invocation
- In questo esempio utilizzeremo per il servizio di naming Java RMI registry
rmiregistry
presente nella directorybin
della jdk,- per permettere al registro di caricare la codebase necessaria dobbiamo avviarlo all'interno della directory contente i file
.class
del nostro progetto, nel costro caso la direcory$Project/build/classes
- per permettere al registro di caricare la codebase necessaria dobbiamo avviarlo all'interno della directory contente i file
- Per i nostri scopi definiamo un nuovo SecurityManager che garantisce una politica
AllPermission
. - Per la lookup degli oggetti remoti utilizzeremo la classe
Naming
. - Material di supporto: Oracle Getting Started Using Java RMI
- Definizione interfaccia remota
Hello.java
public interface Hello extends java.rmi.Remote {
String dimmiQualcosa(String daChi) throws java.rmi.RemoteException;
}
- Implementazione dell'oggetto remoto
HelloImpl.java
import java.rmi.*;
import java.rmi.server.UnicastRemoteObject;
import java.security.Permission;
import java.util.logging.Logger;
public class HelloImpl extends UnicastRemoteObject implements Hello {
private static final long serialVersionUID = -4469091140865645865L;
static Logger logger= Logger.getLogger("global");
public HelloImpl() throws RemoteException { }
public String dimmiQualcosa(String daChi) throws RemoteException {
logger.info("Sto salutando "+daChi);
return "Ciao "+daChi+"!";
}
public static void main(String args[]) throws RemoteException {
//questo codice permette di evitare di scrivere il file policy
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPermission(Permission perm) {
}
@Override
public void checkPermission(Permission perm, Object context) {
}
});
try {
logger.info("Creo l’oggetto remoto...");
HelloImpl obj = new HelloImpl();
logger.info("... ne effettuo il rebind...");
Naming.rebind("HelloServer", obj);
logger.info("... Pronto!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
- Definizione del client che utilizza l'oggetto remoto
HelloClient.java
import java.rmi.*;
import java.util.logging.Logger;
public class HelloClient {
static Logger logger= Logger.getLogger("global");
public static void main(String args[]) {
try {
logger.info("Sto cercando l’oggetto remoto...");
Hello obj = (Hello) Naming.lookup("rmi://localhost/HelloServer");
logger.info("... Trovato! Invoco metodo...");
String risultato = obj.dimmiQualcosa("Pippo");
System.out.println("Ricevuto:"+ risultato); }
catch (Exception e) { e.printStackTrace(); }
}
}
- Esecuzione del progetto
- avviare
rmiregistry
dalla directory~/$PROJECT_NAME/build/classes
porta di defaultrmiregistry
1099. - eseguire
HelloImpl.java
da netbeans tasto destro run file. - eseguire
HelloClient.java
da netbeans tasto destro run file.
- avviare
rmiregistry
locale e export di oggetti remoti
- Server
public void createStubAndBind() throws RemoteException {
MessengerService stub = (MessengerService) UnicastRemoteObject.exportObject((MessengerService) this, 0);
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("MessengerService", stub);
}
- Client
Registry registry = LocateRegistry.getRegistry();
MessengerService server = (MessengerService) registry.lookup("MessengerService");
responseMessage = server.sendMessage("Client Message");
Esercizi Java RMI
- Progettare e realizzare una semplice applicazione RMI client/server per realizzare una calcolatrice:
- Interfaccia remota
Calculator
che definire i metodi per le operazioni di somma, sottrazione, divisione e moltiplicazione; CalculatorImpl
implementa l'interfacciaCalculator
ed estendejava.rmi.server.UnicastRemoteObject
definendo la logica dell'applicazione;CalculatorServer
definisce solo il metodo main e costruisce ed esporta l'oggetto remotoCalculatorImpl
;CalculatorClient
utilizza l'oggetto remotoCalculator
.
- Interfaccia remota
- Progettare e realizzare una applicazione RMI client/server per la gestione delle prenotazioni di un Hotel, con le seguenti operazioni:
- il client deve essere in grado di ottenere la lista delle stanze libere;
- il client può tentare di prenotare una stanza e ottiene un risultato booleano;
- la applicazione deve funzionare in presenza di più client connessi.
- Progettare e realizzare una applicazione RMI client/server per la gestione di un sistema di votazione, con le seguenti operazioni:
- il client deve essere in grado di ottenere la lista dei candidati;
- il client può votare per un candidato e ottiene lo score medio;
- il client può ottenere il risultato delle votazioni (media delle votazioni);
- la applicazione deve funzionare in presenza di più client connessi.
- Progettare e realizzare una applicazione RMI client/server (multi-client) per la gestione di una libreria musicale:
- il client deve essere in grado di ottenere la lista delle canzoni (titolo univoco - link youtube - client name univoco);
- il client può caricare una nuova canzone (titolo univoco - link youtube - client name univoco) visibile a tutti gli altri client;
- il client deve essere in grado di creare delle playlist musicali (sub-set delle canzoni) con titolo univoco visibile a tutti gli altri client;
- il client può eseguire il play di una canzone o di una playlist (il risultato del metodo sono tutti i link youtube);
- il server tiene traccia della riproduzione di una specifica canzone o di una playlist (titolo univoco canzone/playlist, #volte, Lista delle riproduzioni con data e ora);
- il server deve permettere al client di ottenere la lista delle TOP 10 canzoni/playlist riprodotte per ultima settimana, mese e anno.
- Nota 🔗 : ottenere i link da youtube utilizzando il tasto Condividi ➡️ Incorpora dal player youtube;
Introduzione Java Enterprise Edition (Java EE)
- Introduzione Java Enterprise Edition (Java EE)
- Obiettivo
- Contenuti
- Materiale bibliografico
- Altri link interessanti
- Domande di riepilogo
Obiettivo
Comprendere le motivazioni dietro Java Enterprise. Presentare i concetti chiavi dell'architetettura di Java EE e le tecnologie.
Contenuti
- Introduzione
- Architettura
- Multilayer e multitier
- Containers
- Packaging
- Annotazioni e Deployment Descriptor
- L’ecosistema JEE
- Standard
- Storia
- Tecnologie
Materiale bibliografico
- Beginning Java Enterprise Edition: Chapter 1 "Java EE 7 at a Glance"
- Repositoty codice esempi del libro
Altri link interessanti
- Tutorial su Java EE
- Distributed Multitiered Applications
- Packaging Applications
- Java Annotation Processing
Domande di riepilogo
- Quali sono le motivazioni dietro Java Enterprise?
- Che cos’è un Container?
- Quali sono i quattro container di Java EE?
- Quali sono i vantaggi e svantaggi delle annotazioni rispetto ai deployment descriptor?
- Cosa sono le annotazioni?
- Come funziona il meccanismo delle annotazioni?
- Che cos’è un application server?
Contexts and Dependency Injection (CDI)
- Contexts and Dependency Injection (CDI)
- Obiettivo
- Contenuti
- Materiale bibliografico
- Domande di riepilogo
Obiettivo
Presentare il meccanismo di Dependency and Context Injection. Presentare concetti chiavi legati al ciclo di vita e al deployment delle applicazioni enterprise. Mostrare degli esempi di injection, qualificatori, producers, disposers, interceptors e decorators.
Contenuti
Parte 1
- Introduzione
- Dependency Injection
- Life-cycle Management
- Interception
- Loose Coupling and Strong Typing
- Deployment Descriptor
- Esempio di CDI Bean
- Injection
- Qualifiers
- Producers/Disposers
- Scope
Parte 2
- Interceptors
- Classi Interceptor e Ciclo di vita
- Interceptor multipli
- Decorators ed eventi
Materiale bibliografico
- Beginning Java Enterprise Edition:
- Chapter 2 "Context Dependance Injection" da pag. 23 a 66 (tranne "CDI Specifications Overview", "InjectionPoint API", "Beans in Expression Language")
- Descrizione di classi tightly e loosely coupled
- Introduction to Contexts and Dependency Injection for Java EE
- Using Java Reflection
- Comparing JSF Beans, CDI Beans and EJBs
- @Retention
- @interface
- @Transactional
- Beginning Java Enterprise Edition: Chapter 9 "Transactions" pg.302
Domande di riepilogo
- Qual è l'idea alla base del design pattern inversion of control?
- Quali sono i vantaggi del "loose coupling, strong typing"?
- In che modo il ciclo di vita di un bean differisce da quello di un POJO?
- Quali sono i vantaggi derivanti dall'uso degli Interceptor?
- In che modo è possibile definire una sorta di priorità nell'esecuzione di una catena di Interceptor?
- In che modo è possibile realizzare disaccoppiamento nelle applicazioni Java enterprise?
- Qual è il meccanismo che permette di scegliere fra due diverse implementazioni di uno specifico bean?
- Perchè è stato introdotto il concetto di Interceptor Binding?
- Qual è il vantaggio derivante dall'uso dei Decorator?
- Qual è il vantaggio derivante dall'uso degli Eventi?
Laboratorio Java EE ☕
Installazione ambiente di sviluppo
- Utilizzare solo la JDK SE 8.0
- Installare Netbeans
- ⚠️ Utilizzare per il percorso di installazione di Netbeans e dei progetti solo path privi di spazio!
- Nel caso di più versioni della JDK, impostare Netbeans per utilizzare come default la JDK 8.0
- Unix like systems: netbeans/etc/netbeans.conf
- Aggiungere un nuovo server Glassfish 4.1: Tools ➡️ Servers ➡️ Add Servers ...
- Verificare che il server Glassfish utilizza JDK 8, nel caso modificare il file
glassfish/config/asenv.conf
per impostare il percorso corretto della JAVA_HOME
Importare i progetti del libro di testo nel proprio ambiente
Repository codice del libro di testo Beginning Java EE 7
- Code ➡️ Download Zip, Unarchive the project zip, Open Project
- Aprire il progetto chapter02-samples
- Clean and Build Project
- Eseguire il file
Main.java
- Analizzare il codice degli esercizi
- Aprire il progetto chapter02-putting-together e provare ad eseguire il file
Main.java
- Beginning Java EE 7 pg. 57
- Questo esempio utilizza Weld un implementazione CDI per applicazioni Java o Java EE ora sviluppato nell'ambito del progetto Jakarta EE. Weld in questo caso consente di eseguire una applicazione Java SE che utilizza CDI.
Esercizi
0. Un primo esempio con CDI
Creare un nuovo progetto CDI WebApplication
per utilizzare la metodologia CDI per visualizzare tramite una Servlet il risulato della creazione di un istanza di Book
.
- New Project ➡️ Java with ➡️ Ant Java Web ➡️ Web Application
- Includere i sorgenti di
chapter02-putting-together
nel package principale, utilizzando la struttura originale (fare copia e incolla dei sorgenti ossia del packageorg.agoncal.book.javaee7.chapter02
in src) - Includere la dipendenza a J2EE 7, Project X ➡️ Properties ➡️ Libraries ➡️ Add Library ... ➡️
Java EE Web 7 API Library
- Create una nuova Servlet, chiamata
NewServlet
Source Package ➡️ New ➡️ Servlet... - Selezionare la modalità di discovery
all
nel fileWeb Pages/WEB-INF/beans.xml
se non presente crearlo con new file inWeb Pages/WEB-INF/beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
bean-discovery-mode="all">
</beans>
- Utilizzare la annotazione
@Inject
per includere una nuova istanzaBookService
nel codice della servlet
public class MainServerlet extends HttpServlet {
@Inject
BookService b;
...
}
- Utilizzare il servizio BookService per costruire un nuovo libro e visualizzare risultato nell'output della servlet in elemento HTML
<h3>
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try ( PrintWriter out = response.getWriter()) {
/* TODO output your page here. You may use following sample code. */
out.println("<!DOCTYPE html>"); out.println("<html>");
out.println("<head>");
out.println("<title >Servlet NewServlet </title >"); out.println("</head>");
out.println("<body>"); out.println("<h1>Servlet NewServlet at " +
request.getContextPath() + "</h1>");
Book book = b.createBook("H2G2", 12.5f, "Geeky scifi Book");
out.println("<h3>Libro creato:"+book+"</h3>"); out.println("</body>"); out.println("</html>");
}
}
1. 🗺️ Esercizio Explore CDI - Applicazione Hello World CDI
Realizzare da zero una nuova applicazione Hello World che utilizza una servlet per visualizzare in una pagina Web un messaggio di benvenuto.
- La stringa viene elaborata tramite un particolare MB che implementa l'interfaccia
Welcome
che definisce i metedigetWelcomeMessageLowercase()
egetWelcomeMessageUppercase()
. - E' possibile utilizzare Injection, Qualifiers, e Producers.
- Provare a definire un producer per la stringa
hello world
e un producer per la stringaHELLO WORLD
in maiuscolo specificando due diversi qualifiers. - Implementare una servlet che visualizza il messaggio
hello world
eHELLO WORLD
in maiuscolo invocando i corrispondenti metodi dell'MB.
2. ⏯️ Esercizio Music Library primi 👣
Gestire una libreria musicale definendo un oggetto Song e un oggetto Library che è un MB che tramite l'utilizzo di Producers dichiara un ArrayList<Song>
.
- Il risultato dell'architettura deve permettere di utilizzare il seguente codice nella classe Library:
@Inject ArrayList<Song> db;
, preinizializzato con un fissato insieme di Song- la classe Library permette di gestire tutte le successive operazioni possibili di una libreria musicale (aggiungi, cancella, trova per ID, trova per nome, etc.).
- Realizzare una serverlet che permette di visualizzare il contenuto della libreria in una pagina HTML.
3. Verifica del funzionamento di Safe Exam Browser
Approfondimenti
Contexts and Dependency Injection (CDI)
- Contexts and Dependency Injection (CDI)
- Obiettivo
- Contenuti
- Materiale bibliografico
- Domande di riepilogo
Obiettivo
Presentare il meccanismo di Dependency and Context Injection. Presentare concetti chiavi legati al ciclo di vita e al deployment delle applicazioni enterprise. Mostrare degli esempi di injection, qualificatori, producers, disposers, interceptors e decorators.
Contenuti
Parte 1
- Introduzione
- Dependency Injection
- Life-cycle Management
- Interception
- Loose Coupling and Strong Typing
- Deployment Descriptor
- Esempio di CDI Bean
- Injection
- Qualifiers
- Producers/Disposers
- Scope
Parte 2
- Interceptors
- Classi Interceptor e Ciclo di vita
- Interceptor multipli
- Decorators ed eventi
Materiale bibliografico
- Beginning Java Enterprise Edition:
- Chapter 2 "Context Dependance Injection" da pag. 23 a 66 (tranne "CDI Specifications Overview", "InjectionPoint API", "Beans in Expression Language")
- Descrizione di classi tightly e loosely coupled
- Introduction to Contexts and Dependency Injection for Java EE
- Using Java Reflection
- Comparing JSF Beans, CDI Beans and EJBs
- @Retention
- @interface
- @Transactional
- Beginning Java Enterprise Edition: Chapter 9 "Transactions" pg.302
Domande di riepilogo
- Qual è l'idea alla base del design pattern inversion of control?
- Quali sono i vantaggi del "loose coupling, strong typing"?
- In che modo il ciclo di vita di un bean differisce da quello di un POJO?
- Quali sono i vantaggi derivanti dall'uso degli Interceptor?
- In che modo è possibile definire una sorta di priorità nell'esecuzione di una catena di Interceptor?
- In che modo è possibile realizzare disaccoppiamento nelle applicazioni Java enterprise?
- Qual è il meccanismo che permette di scegliere fra due diverse implementazioni di uno specifico bean?
- Perchè è stato introdotto il concetto di Interceptor Binding?
- Qual è il vantaggio derivante dall'uso dei Decorator?
- Qual è il vantaggio derivante dall'uso degli Eventi?
Contenuti
Parte 1
- Introduzione a JPA
- Entità
- Definizione
- Anatomia
- Queries
- Object-Relational Mapping (ORM)
- Entity Manager
- Persistence Unit
- Ciclo di vita delle Entità
- Specifiche JPA
- Esempio completo di JPA
- Managing Persistent Objects
Parte 2
- Come si manipolno le entita con un Entity Manager
- JPQL
- tipi di query
- Interazione col ciclo di vita
- callbacks
- listeners
Materiale bibliografico
- "Beginning Java Enterprise Edition": Cap. 4 (tranne "Integration with Bean Validation", "JPA Specification Overview")
- "Beginning Java Enterprise Edition": Cap. 5 (tranne "Composite Primary Keys", da pag 129 a 148) e Cap. 6 (tranne "Fetching Relationships", da pag 161 a 176; "Type-Safe Criteria API", "Cache API", da pag 209 a 216)
- Querying JPA Entities with JPQL and Native SQL
Domande di riepilogo
- Qual è la differenza fra una entità ed un oggetto?
- A cosa serve l'annotazione @GeneratedValue?
- Qual è l'elemento discriminante per distinguere una entità da un POJO?
- Qual è l'API fondamentale per la gestione delle operazioni sulle entità?
- Quali sono le caratteristiche e le funzionalità più importanti della persistence unit?
- Descrivere il ciclo di vita di una entità
- Descrivere i tipi di relazioni in un database relazionale
- A cosa serve l'annotazione @JoinColumn?
- Definizione e funzionalità di un Persistence Context
- Descrivere i vari tipi di query definiti da JPQL
persistence.xml
visto a lezione
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="PJPAPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>pjpa.Person</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/Paolo;create=true"/>
<property name="javax.persistence.jdbc.user" value="paolo"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/>
<property name="javax.persistence.jdbc.password" value="paolo"/>
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="eclipselink.logging.level" value="INFO"/>
<property name="javax.persistence.schema-generation.scripts.create-target" value="pjpa-create.ddl"/>
<property name="javax.persistence.schema-generation.scripts.drop-target" value="pjpa-drop.ddl"/>
</properties>
</persistence-unit>
</persistence>
Contenuti
Parte 1
- Introduzione a JPA
- Entità
- Definizione
- Anatomia
- Queries
- Object-Relational Mapping (ORM)
- Entity Manager
- Persistence Unit
- Ciclo di vita delle Entità
- Specifiche JPA
- Esempio completo di JPA
- Managing Persistent Objects
Parte 2
- Come si manipolno le entita con un Entity Manager
- JPQL
- tipi di query
- Interazione col ciclo di vita
- callbacks
- listeners
Materiale bibliografico
- "Beginning Java Enterprise Edition": Cap. 4 (tranne "Integration with Bean Validation", "JPA Specification Overview")
- "Beginning Java Enterprise Edition": Cap. 5 (tranne "Composite Primary Keys", da pag 129 a 148) e Cap. 6 (tranne "Fetching Relationships", da pag 161 a 176; "Type-Safe Criteria API", "Cache API", da pag 209 a 216)
- Querying JPA Entities with JPQL and Native SQL
Domande di riepilogo
- Qual è la differenza fra una entità ed un oggetto?
- A cosa serve l'annotazione @GeneratedValue?
- Qual è l'elemento discriminante per distinguere una entità da un POJO?
- Qual è l'API fondamentale per la gestione delle operazioni sulle entità?
- Quali sono le caratteristiche e le funzionalità più importanti della persistence unit?
- Descrivere il ciclo di vita di una entità
- Descrivere i tipi di relazioni in un database relazionale
- A cosa serve l'annotazione @JoinColumn?
- Definizione e funzionalità di un Persistence Context
- Descrivere i vari tipi di query definiti da JPQL
persistence.xml
visto a lezione
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="PJPAPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>pjpa.Person</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/Paolo;create=true"/>
<property name="javax.persistence.jdbc.user" value="paolo"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/>
<property name="javax.persistence.jdbc.password" value="paolo"/>
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="eclipselink.logging.level" value="INFO"/>
<property name="javax.persistence.schema-generation.scripts.create-target" value="pjpa-create.ddl"/>
<property name="javax.persistence.schema-generation.scripts.drop-target" value="pjpa-drop.ddl"/>
</properties>
</persistence-unit>
</persistence>
Esercizio 1 - BookStore
Scrivere un programma Java usando JPA che simuli le operazioni principali di un negozio di libri (aggiunta, rimozione e lista dei libri).
- Da Derby, creare il database con un utente associato. Fate attenzione a specificare user name e password non vuote.
- Creare una classe Entity Book caratterizzata da:
- titolo, prezzo, descrizione, isbn e categoria.
- Creare una classe Main in cui l’utente può aggiungere e rimuovere un libro e permetta di fare una ricerca per filtri (titolo, categoria, isbn).
Note:
- Nuovo progetto Java with Ant ➡️ Java Application
- Creare il file
META-INF/persistence.xml
da Netbeans - Aggiungere al progetto le librerie:
Java EE 7 API Library
,Java DB Driver
,Eclipse Link (JPA 2.1)
- Se utilizzate come schema generation della persistence unit drop-and-create, non occorre che creiate manualmente le tabelle
- Esempio di file persistence
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1">
<persistence-unit name="exercise_pu" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider </provider>
<class>pd.bookstore.Book</class>
<properties>
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/BookStore;create=true"/>
<property name="javax.persistence.jdbc.password" value="abc"/>
<property name="javax.persistence.jdbc.user" value="abc"/>
</properties>
</persistence-unit>
</persistence>
Esercizio 2 - Job Scheduling
Scrivere un programma Java usando JPA che simuli le operazioni di una azienda che assegna a ogni dipendente un particolare lavoro (Job). Ad ogni dipendente (Person) si associa anche un particolare indirizzo (Address).
public class Person {
private String id;
private String firstName;
private String lastName;
private Character middleInitial;
private Address address;
private Job job;
/*...*/
}
public class Address {
private String id;
private String street1;
private String street2;
private String city;
private String state;
private String zip;
/*...*/
}
public class Job {
private Long id;
private String title;
private Float salary;
private String employeedId;
/*...*/
}
Nota: vedere Cascading Events pg.191 libro di testo Java EE7
Esercizio 2.1
Permettere il mapping di diversi Job per un singolo dipendente.
@OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
private List<Job> jobs = new ArrayList<>();
Esercizio 2.2
Definire le seguenti NamedQuery per l'entità Person:
@NamedQueries({
@NamedQuery(name = FIND_ALL, query = " ... "),
@NamedQuery(name = FIND_BY_FIRST_NAME, query = " ... "),
@NamedQuery(name = FIND_BY_LAST_NAME, query = " ... "),
@NamedQuery(name = FIND_BY_FIRST_LAST_NAME, query = " ... "),
@NamedQuery(name = FIND_BY_ADDRESS, query = " ... "),
@NamedQuery(name = FIND_BY_ID, query = " ... "),
@NamedQuery(name = FIND_BY_JOB, query = " ... "),
})
Esercizio 2.3
Definire un POJO che permetta di popolare il database come segue.
public class DatabasePopulator {
private Person p1, p2, p3, p4;
private Address a1,a2;
private Job j1,j2,j3,j4,j5,j6,j7,j8;
private void populateDB(){
/*here code*/
}
private void clearDB(){
/*here code*/
}
}
Esercizio 2.4
Scrivere una classe Main che permette di popolare il DB e permette di eseguire le diverse NamedQuery e di visualizzare il risulato (utilizzare @Inject
e/o @PersistenceUnit(unitName="name")
).
Contenuti
Parte 1
- Introduzione agli EJB
- Come sono fatti gli EJB
- Tipi di EJB
- Stateless
- Stateful
- Singleton
- Come usare un EJB
Parte 2
- Ciclo di Vita dei Session Beans
- Autorizzazioni
- Autorizzazione dichiarativa
- Autorizzazione da programma
- Transazioni
- Cosa sono
- Container-managed
- Bean-Managed
- Esercizi EJB con NetBeans
Materiale bibliografico per lo studio
- "Beginning Java Enterprise Edition": Cap. 7, escludere da pag 247 a pag 256
- "Beginning Java Enterprise Edition": Cap. 8, escludere Timer Service
- "Beginning Java Enterprise Edition": Cap. 9, solo "Understanding Transactions", "Transaction Support in EJB", "Container-managed transactions" fino a pag. 296
@Inject
vs@EJB
- Managing Concurrent Access in a Singleton Session Bean
Alcune domande di riepilogo
- Qual è il ciclo di vita di un bean?
- Qual è il vantaggio dell'utilizzo di JNDI?
- Quali sono le differenze tra i tre differenti tipi di beans in termini di chiamate dai clients?
- Qual è il caso d'uso più comune per un singleton bean?
- Qual è il vantaggio dell'suo del: "Programmatic Authorization"?
- Quali sono le principali differenze fra Container-Managed e Bean-managed transactions?
- Packaging e deploying
- Come invocare EJB
Contenuti
Parte 1
- Introduzione agli EJB
- Come sono fatti gli EJB
- Tipi di EJB
- Stateless
- Stateful
- Singleton
- Come usare un EJB
Parte 2
- Ciclo di Vita dei Session Beans
- Autorizzazioni
- Autorizzazione dichiarativa
- Autorizzazione da programma
- Transazioni
- Cosa sono
- Container-managed
- Bean-Managed
- Esercizi EJB con NetBeans
Materiale bibliografico per lo studio
- "Beginning Java Enterprise Edition": Cap. 7, escludere da pag 247 a pag 256
- "Beginning Java Enterprise Edition": Cap. 8, escludere Timer Service
- "Beginning Java Enterprise Edition": Cap. 9, solo "Understanding Transactions", "Transaction Support in EJB", "Container-managed transactions" fino a pag. 296
@Inject
vs@EJB
- Managing Concurrent Access in a Singleton Session Bean
Alcune domande di riepilogo
- Qual è il ciclo di vita di un bean?
- Qual è il vantaggio dell'utilizzo di JNDI?
- Quali sono le differenze tra i tre differenti tipi di beans in termini di chiamate dai clients?
- Qual è il caso d'uso più comune per un singleton bean?
- Qual è il vantaggio dell'suo del: "Programmatic Authorization"?
- Quali sono le principali differenze fra Container-Managed e Bean-managed transactions?
- Packaging e deploying
- Come invocare EJB
- Esercizio 0 - Hello World EJB
- Esercizio 1 - Music Library 🎵📚 (warm-up 🏋)
- Esercizio 2 - Music Library++ 🎵📚
- Esercizio 3 - PDtify 🎵 ⏯️
- Esercizi Bonus
🚀 Se avete problemi con la lookup dei vostri bean potete verificare che state utilizzando il dominio corretto con i parametri di default nel file
[USER_HOME]/GlassFish_Server/glassfish/domains/domain1/config/domain.xml
. Il pacchetto[USER_HOME]/GlassFish_Server/glassfish/lib/gf-client.jar
carica configurazioni per l'InitialContext di default (GlassFish Server Administration Guide).
❓ Esempio di setting della porta per il servizio IIOP necessario per il discovery di RMI:
Properties props = new Properties();
props.setProperty("java.naming.factory.initial",
"com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs",
"com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state",
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
Context ctx = new InitialContext(props);
Esercizio 0 - Hello World EJB
Ripetere l'esercitazione visto a lezione per la definizione di un nuovo stateless EJB HelloWorld
che implementa un metodo sayHello(String text)
che restituisce una stringa di saluto. Il client deve essere un applicazione Java che invoca il metodo remoto sayHello("Hello my name is "+name)
e stampa il risultato a console.
🚀 Includere nell'applicazione Java SE Client il pacchetto
[USER_HOME]/GlassFish_Server/glassfish/lib/gf-client.jar
per la lookup del bean remoto. Definendo la sua interfaccia remotaHelloWorldRemote.java
come segue:
@Remote
public interface HelloWorldEJBRemote{
public String sayHello(String name);
}
Esercizio 1 - Music Library 🎵📚 (warm-up 🏋)
Creare due progetti:
- MusicLibrary: New Project ➡️ Java with Ant ➡️ Java Enterprise ➡️ EJB Module
- MusicLibraryClient: New Project ➡️ Java with Ant ➡️ Java Application (con una main class)
Music Library
Creare un nuovo pacchetto Source Packages ➡️ New ➡️ Java Package it.pd2024.musiclibrary
Definizione entità e persistenza
Song.java
definisce un entità persistente che identifica un brano musicale.
//import packages
import static it.pd2022.musiclibrary.Song.TROVA_TUTTE;
@Entity
@NamedQueries({
@NamedQuery(name = TROVA_TUTTE, query = "SELECT s FROM Song s"),
})
public class Song implements Serializable{
public static final String TROVA_TUTTE = "Song.trovaTutteCanzoni";
@Id @GeneratedValue
private Long ID;
private String authors;
private String name;
private URL url; //link youtube
public Song() { }
public Song(String authors, String name, URL url) {
this.authors = authors;
this.name = name;
this.url = url;
}
//Insert code -> getters and setter
//Insert code -> toString()
}
Nota: ottenere i link da youtube utilizzando il tasto Condividi ➡️ Incorpora dal player youtube.
- Dobbiamo denifire una nuova Persistence Unit in modalità JTA:
MusicLibraryPU
- New ➡️ Persistence Unit, e come segue:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="MusicLibraryPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:global/jdbc/MusicLibraryDataSource</jta-data-source>
<properties>
<property name="eclipselink.target-database" value="DERBY"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
</persistence>
- Creaiamo un nuovo Singleton istanziato in fase di avvio dell'applicazione che consente l'inizializzazione e la definizione di un nuovo database e datasource per la nostra applicazione:
DatabasePopulator.java
@Singleton
@Startup
@DataSourceDefinition(
className ="org.apache.derby.jdbc.EmbeddedDataSource", name ="java:global/jdbc/MusicLibraryDataSource",
user ="APP",
password ="APP",
databaseName ="MusicLibraryDB",
properties = {"connectionAttributes=;create=true"}
)
public class DatabasePopulator {
//PER ORA VUOTO
}
🚀 A questo punto la parte base della persistenza è terminata e possiamo eseguire la build del progetto e il deploy su GlassFish.
Definizione della logica della nostra applicazione
Le funzionalità dell'applicazione saranno definite in un enterprise java bean stateless chiamato MusicLibrary.java
, che saranno offerte ai client (applicazioni Java) tramite l'invocazione di metodi remoti, quindi dovremo definire ed implementare un interfaccia remota MusicLibraryRemote.java
.
@Stateless
@LocalBean
public class MusicLibrary implements MusicLibraryRemote{
@Inject
private EntityManager em;
public List<Song> findSongs() {
TypedQuery<Song> query = em.createNamedQuery(Song.TROVA_TUTTE, Song.class);
return query.getResultList();
}
public Song createSong( Song song) {
em.persist(song);
return song;
}
}
@Remote
public interface MusicLibraryRemote {
public List<Song> findSongs();
public Song createSong(Song song);
}
Nella definzione del nostro EJB MusicLibrary utilizziamo l'iniezione di una dipendenza ad un EntityManager
di conseguenza dobbiamo definire un metodo per la "produzione" di tale oggetto in una classe DatabaseProducer.java
come segue.
public class DatabaseProducer {
@Produces
@PersistenceContext(unitName ="MusicLibraryPU")
private EntityManager em;
}
- Prima di proseguire dobbiamo include nel nostro progetto la definizione del file
beans.xml
che ci permette di impostare la disscovery mode dei nostri beans a all.- New File ➡️ Contexts and Dependency Injection ➡️ beans.xml, impostare
bean-discovery-mode="all"
- New File ➡️ Contexts and Dependency Injection ➡️ beans.xml, impostare
- A questo punto possiamo completare il nostro
DatabasePopulator.java
inserendo nel database alcune canzoni di esempio ed utilizzando l'EJB MusicLibrary. Possiamo inserire la definizione del seguente metodo:
private Song s1, s2;
@Inject
private MusicLibrary lib;
@PostConstruct
private void populateDB() {
try {
s1 = new Song("Queen","We Are The Champions", new URL("https://www.youtube.com/embed/KXw8CRapg7k"));
s2 = new Song("Home Free", "Sea Shanty Medley", new URL("https://www.youtube.com/embed/lLGLUSzzuWU"));
lib.createSong(s1);
lib.createSong(s2);
} catch (MalformedURLException ex) {
Logger.getLogger(DatabasePopulator.class.getName()).log(Level.SEVERE, null, ex);
}
}
🚀 La parte di logica è terminata e possiamo eseguire la build del progetto e il deploy su GlassFish.
Music Library Client
Prima di procedere con lo sviluppo del nostro java client dobbiamo specificare le dipendenze necessarie:
- 1️⃣ Progetto
MusicLibrary
: Properties ➡️ Libraries ➡️ Classpath ➕ ➡️ Add Projects... ➡️MusicLibrary
- 2️⃣ Libreria
gf-client.jar
: Properties ➡️ Libraries ➡️ Classpath ➕ ➡️ Add JAR/Folder ➡️[USER_HOME]/GlassFish_Server/glassfish/lib/gf-client.jar
, la libreria si trova nella vostra installazione di glassfish nel path specificato.
public class MusicLibraryClient {
public static void main(String[] args) throws NamingException {
Context ctx = new InitialContext();
MusicLibraryRemote ejb = (MusicLibraryRemote) ctx.lookup("java:global/MusicLibrary/MusicLibrary!it.pd2022.musiclibrary.MusicLibraryRemote");
List<Song> lista = ejb.findSongs();
for(Song s: lista)
System.out.println(s);
}
}
🚀 Il client della nostra applicazione è pronto possiamo eseguirlo. 🎯 Output:
run: nov 06, 2022 1:32:13 PM com.sun.enterprise.v3.server.CommonClassLoaderServiceImpl findDerbyClient INFORMAZIONI: Cannot find javadb client jar file, derby jdbc driver will not be available by default. Song{ID=2, authors=Home Free, name=Sea Shanty Medley, url=https://www.youtube.com/watch?v=lLGLUSzzuWU&ab_channel=HomeFree} Song{ID=1, authors=Queen, name=We Are The Champions, url=https://www.youtube.com/watch?v=KXw8CRapg7k&ab_channel=QueenVEVO} BUILD SUCCESSFUL (total time: 2 seconds)
Nota l'indirizzo JNDI dell'interfaccia remota del bean MusicLibrary può essere visualizzato nella console di output di glassfish subito dopo il deploy dell'applicazione.
Esercizio 2 - Music Library++ 🎵📚
Aggiungere le seguenti funzionalità al progetto MusicLibrary:
-
Ampliare la definzione di
Song
inserendo:- anno di rilascio,
- numero di visualizzazioni (numero di volte in cui il bravo è stato riprodotto),
- lyrics;
- specificare delle nuove NamedQuery che permettano la ricerca delle canzoni per anno di rilascio, nome autore, nome del brano.
-
Definire una nuova entità
Playlist
che consente di collezionare moltepliciSong
, specificando- nome,
- autore,
- tipologia,
- descrizione,
- data in cui è stato effettuato l'ultimo aggiornamento.
Le playlist possono essere create, modificate, visualizzate, ricercate per tipologia, ed eliminate senza eliminare dal database i brani contenuti.
-
Ampliare la definizione di
MusicLibrary
per supportare le precedenti nuove entità e funzionalità.- Introdurre la definizione di una metodo
play(song_ID)
che permette di ottenere la URL di una song, questo metodo va intercettato per aggiornare il numero di volte che un particolare brano viene riprodotto. Modificare il filebeans.xml
per aggiungere la definizione del nuovo interceptor:
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all"> <interceptors> <class>org.agoncal.book.javaee7.chapter02.LoggingInterceptor</class> </interceptors> </beans>
- Opzionale: estendere la definizione del metodo play per la riproduzione di un lista di brani ottenuti da una particolare playlist.
- Introdurre la definizione di una metodo
Mofificare la classe main di MusicLibraryClient
per il testing e la verifica di tutte le funzionalità di MusicLibrary
.
Esercizio 3 - PDtify 🎵 ⏯️
Obiettivo: creare un enterprise java application con due moduli principali un modulo di business/persistenza e un modulo di presentazione web che permetta la gestione di una libreria musicale evoluta (playlist) utilizzando come player di riproduzione web le API di Youtube Embedded.
- ⚠️ prima di procedere effettuare l'undeploy del progetto precedente dal server glassfish.
PDtify
: New Project ➡️ Java with Ant ➡️ Java Enterprise ➡️ Enterprise Application- Output in Netbeans:
PDtify
enterprise application.PDtify-ejb
un modulo ejb.PDtify-web
un modulo web.
- Riportare il progetto
MusicLibray
nel moduloPDtify-ejb
. - Costruire un nuovo client web utilizzando una servelet
MusicPlayer
che sfrutta l'EJBMusicLibrary
per offrire attraverso una pagina web tutte le funzionalità dell'applicazione. Quando si crea la Servlet specificare Add information to the deployment descriptor (web.xml) passaggio 2 del wizard di creazione della Servlet. - Note:
- riportare nel modulo ejb tutte le definizione di persistence e beans.xml;
- quando si eseguono le operazioni di build, deploy, e run del progetto vanno lanciate dal progetto principale entrprise
PDtify
; - per specificare che di default la index della nostra applicazione sarà la Servlet
MusicPlayer
modificare il filePDtify-war/Web Pages/WEB-INF/web.xml
come segue:<servlet-mapping> <servlet-name>MusicPlayer</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
play()
la visualizzazione del metodo play può essere ottenuta utilizzando l'embedding della URL di un brano all'interno di un iframe:Song s = new Song("Queen","We Are The Champions", new URL("https://www.youtube.com/embed/KXw8CRapg7k")); out.println("<iframe width=\"420\""+ "height=\"315\"\n" + "src=\""+s.getUrl()+"\">\n" + "</iframe>");
Esercizi Bonus
Esercizio B.1 - Calcolatrice EJB
Scrivere un client Java che invoca degli EJB sul server che implementano un servizio di calcolatrice per tipi float. La calcolatrice offre tre metodi, tutti prendono in input due operandi di tipo float
e restituiscono un float
:
add(float,float)
sub(float,float)
multiply(float,float)
Il server offre inoltre un servizio di counting count()
che restituisce il numero di operazioni effettuate da tutti i clienti dall’avvio del server. Il client deve offrire da console un interfaccia che permetta di effettuare tutte le operazioni da remoto.
Esercizio B.2 - Calcolatrice EJB basata su stack
Scrivere un client Java che invoca degli Enterprise EJB sul server che implementano un servizio di calcolatrice basata su stack per tipi float
. La calcolatrice offre cinque metodi. Tre di questi metodi rappresentano operazioni aritmetiche che non prendono input e operano direttamente sui dati nello stack: add()
, sub()
, multiply()
.
In aggiunta, il server offre il metodovoid push(float)
e float pop()
per la gestione dello stack. Nota che l’unico metodo che restituisce valori è la pop()
. Le operazione aritmetiche eseguono implicitamente due pop()
per prelevare gli operandi e una push()
per salvare il valore di ritorno.
Esempio di esecuzione del servizio:
push(3)
,push(4)
,add()
,pop()
➡️ 7push(3)
,push(4)
,multiply()
,pop()
➡️ 12push(3)
,push(4)
,push(1)
,add()
,pop()
➡️ 5push(3)
,push(4)
,push(1)
,add()
,add()
,pop()
➡️ 8
Avanzato: gestire i meccanismi di attivazione e passivazione.
Esercizio B.3 - Calcolatrice EJB basata su stack persistente
Estendere il servizio di calcolatrice basata su stack implementata nell’esercizio precedente aggiungendo un livello di persistenza dello stack. In particolare, ad ogni operazione, lo stack deve essere salvato su database. All’interfaccia del servizio verrà aggiunto il metodo loadStack(String stackName)
e saveStack(String stackName)
che consentono all’utente di caricare lo stack da database . Se il client non invoca la loadStack()
, la sessione si avvia con uno stack vuoto. Lo stack puo essere salvato nel formato piu appropriato, anche come stringa.
Al fine di completare l’esercizo, occorre
- Implementare il metodo
loadStack(String username)
. - Implementare il metodo
saveStack(String username)
. - Implementare un metodo
stackList()
che restituisce tutti i nomi degli stack salvati su database. - Implementare un interceptor che, alla fine dell’interazione con un client, stampa una lista dei stackName usati da quell’utente in quella sessione.
Contenuti
Parte 1
- Introduzione
- Messaging
- Java Messaging Service API
- Message Producers
- Message Consumers
- Anatomia di un messaggio
- Meccanismi di affidabilità
Parte 2
- Message-Driven Beans
- Un esempio conclusivo
- Il codice
- Configurazione
- I progetti
- Esercizi
Materiale bibliografico
- "Beginning Java Enterprise Edition": Cap. 13
- Oracle GlassFish Server Message Queue 4.5 Technical Overview. Cap. 1, Cap. 2, Cap. 3, Cap. 4 (cenni)
Domande di riepilogo
- Quali sono le principali differenze fra il modello Point-to-Point ed il modello Publish-Subscribe?
- Cosa sono i Message-Driven Beans?
- Cosa sono gli Administered Objects?
- Qual è la differenza fra Synchronous Delivery e Asynchronous Delivery?
- Quali sono i principali meccanismi di affidabilità?
- Quali eccezioni si possono gestire con gli MDB?
Contenuti
Parte 1
- Introduzione agli EJB
- Come sono fatti gli EJB
- Tipi di EJB
- Stateless
- Stateful
- Singleton
- Come usare un EJB
Parte 2
- Ciclo di Vita dei Session Beans
- Autorizzazioni
- Autorizzazione dichiarativa
- Autorizzazione da programma
- Transazioni
- Cosa sono
- Container-managed
- Bean-Managed
- Esercizi EJB con NetBeans
Materiale bibliografico per lo studio
- "Beginning Java Enterprise Edition": Cap. 7, escludere da pag 247 a pag 256
- "Beginning Java Enterprise Edition": Cap. 8, escludere Timer Service
- "Beginning Java Enterprise Edition": Cap. 9, solo "Understanding Transactions", "Transaction Support in EJB", "Container-managed transactions" fino a pag. 296
@Inject
vs@EJB
- Managing Concurrent Access in a Singleton Session Bean
Alcune domande di riepilogo
- Qual è il ciclo di vita di un bean?
- Qual è il vantaggio dell'utilizzo di JNDI?
- Quali sono le differenze tra i tre differenti tipi di beans in termini di chiamate dai clients?
- Qual è il caso d'uso più comune per un singleton bean?
- Qual è il vantaggio dell'suo del: "Programmatic Authorization"?
- Quali sono le principali differenze fra Container-Managed e Bean-managed transactions?
- Packaging e deploying
- Come invocare EJB
- Esercizio 0 - Hello World EJB
- Esercizio 1 - Music Library 🎵📚 (warm-up 🏋)
- Esercizio 2 - Music Library++ 🎵📚
- Esercizio 3 - PDtify 🎵 ⏯️
- Esercizi Bonus
🚀 Se avete problemi con la lookup dei vostri bean potete verificare che state utilizzando il dominio corretto con i parametri di default nel file
[USER_HOME]/GlassFish_Server/glassfish/domains/domain1/config/domain.xml
. Il pacchetto[USER_HOME]/GlassFish_Server/glassfish/lib/gf-client.jar
carica configurazioni per l'InitialContext di default (GlassFish Server Administration Guide).
❓ Esempio di setting della porta per il servizio IIOP necessario per il discovery di RMI:
Properties props = new Properties();
props.setProperty("java.naming.factory.initial",
"com.sun.enterprise.naming.SerialInitContextFactory");
props.setProperty("java.naming.factory.url.pkgs",
"com.sun.enterprise.naming");
props.setProperty("java.naming.factory.state",
"com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
props.setProperty("org.omg.CORBA.ORBInitialHost", "localhost");
props.setProperty("org.omg.CORBA.ORBInitialPort", "3700");
Context ctx = new InitialContext(props);
Esercizio 0 - Hello World EJB
Ripetere l'esercitazione visto a lezione per la definizione di un nuovo stateless EJB HelloWorld
che implementa un metodo sayHello(String text)
che restituisce una stringa di saluto. Il client deve essere un applicazione Java che invoca il metodo remoto sayHello("Hello my name is "+name)
e stampa il risultato a console.
🚀 Includere nell'applicazione Java SE Client il pacchetto
[USER_HOME]/GlassFish_Server/glassfish/lib/gf-client.jar
per la lookup del bean remoto. Definendo la sua interfaccia remotaHelloWorldRemote.java
come segue:
@Remote
public interface HelloWorldEJBRemote{
public String sayHello(String name);
}
Esercizio 1 - Music Library 🎵📚 (warm-up 🏋)
Creare due progetti:
- MusicLibrary: New Project ➡️ Java with Ant ➡️ Java Enterprise ➡️ EJB Module
- MusicLibraryClient: New Project ➡️ Java with Ant ➡️ Java Application (con una main class)
Music Library
Creare un nuovo pacchetto Source Packages ➡️ New ➡️ Java Package it.pd2024.musiclibrary
Definizione entità e persistenza
Song.java
definisce un entità persistente che identifica un brano musicale.
//import packages
import static it.pd2022.musiclibrary.Song.TROVA_TUTTE;
@Entity
@NamedQueries({
@NamedQuery(name = TROVA_TUTTE, query = "SELECT s FROM Song s"),
})
public class Song implements Serializable{
public static final String TROVA_TUTTE = "Song.trovaTutteCanzoni";
@Id @GeneratedValue
private Long ID;
private String authors;
private String name;
private URL url; //link youtube
public Song() { }
public Song(String authors, String name, URL url) {
this.authors = authors;
this.name = name;
this.url = url;
}
//Insert code -> getters and setter
//Insert code -> toString()
}
Nota: ottenere i link da youtube utilizzando il tasto Condividi ➡️ Incorpora dal player youtube.
- Dobbiamo denifire una nuova Persistence Unit in modalità JTA:
MusicLibraryPU
- New ➡️ Persistence Unit, e come segue:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="MusicLibraryPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>java:global/jdbc/MusicLibraryDataSource</jta-data-source>
<properties>
<property name="eclipselink.target-database" value="DERBY"/>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
<property name="eclipselink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
</persistence>
- Creaiamo un nuovo Singleton istanziato in fase di avvio dell'applicazione che consente l'inizializzazione e la definizione di un nuovo database e datasource per la nostra applicazione:
DatabasePopulator.java
@Singleton
@Startup
@DataSourceDefinition(
className ="org.apache.derby.jdbc.EmbeddedDataSource", name ="java:global/jdbc/MusicLibraryDataSource",
user ="APP",
password ="APP",
databaseName ="MusicLibraryDB",
properties = {"connectionAttributes=;create=true"}
)
public class DatabasePopulator {
//PER ORA VUOTO
}
🚀 A questo punto la parte base della persistenza è terminata e possiamo eseguire la build del progetto e il deploy su GlassFish.
Definizione della logica della nostra applicazione
Le funzionalità dell'applicazione saranno definite in un enterprise java bean stateless chiamato MusicLibrary.java
, che saranno offerte ai client (applicazioni Java) tramite l'invocazione di metodi remoti, quindi dovremo definire ed implementare un interfaccia remota MusicLibraryRemote.java
.
@Stateless
@LocalBean
public class MusicLibrary implements MusicLibraryRemote{
@Inject
private EntityManager em;
public List<Song> findSongs() {
TypedQuery<Song> query = em.createNamedQuery(Song.TROVA_TUTTE, Song.class);
return query.getResultList();
}
public Song createSong( Song song) {
em.persist(song);
return song;
}
}
@Remote
public interface MusicLibraryRemote {
public List<Song> findSongs();
public Song createSong(Song song);
}
Nella definzione del nostro EJB MusicLibrary utilizziamo l'iniezione di una dipendenza ad un EntityManager
di conseguenza dobbiamo definire un metodo per la "produzione" di tale oggetto in una classe DatabaseProducer.java
come segue.
public class DatabaseProducer {
@Produces
@PersistenceContext(unitName ="MusicLibraryPU")
private EntityManager em;
}
- Prima di proseguire dobbiamo include nel nostro progetto la definizione del file
beans.xml
che ci permette di impostare la disscovery mode dei nostri beans a all.- New File ➡️ Contexts and Dependency Injection ➡️ beans.xml, impostare
bean-discovery-mode="all"
- New File ➡️ Contexts and Dependency Injection ➡️ beans.xml, impostare
- A questo punto possiamo completare il nostro
DatabasePopulator.java
inserendo nel database alcune canzoni di esempio ed utilizzando l'EJB MusicLibrary. Possiamo inserire la definizione del seguente metodo:
private Song s1, s2;
@Inject
private MusicLibrary lib;
@PostConstruct
private void populateDB() {
try {
s1 = new Song("Queen","We Are The Champions", new URL("https://www.youtube.com/embed/KXw8CRapg7k"));
s2 = new Song("Home Free", "Sea Shanty Medley", new URL("https://www.youtube.com/embed/lLGLUSzzuWU"));
lib.createSong(s1);
lib.createSong(s2);
} catch (MalformedURLException ex) {
Logger.getLogger(DatabasePopulator.class.getName()).log(Level.SEVERE, null, ex);
}
}
🚀 La parte di logica è terminata e possiamo eseguire la build del progetto e il deploy su GlassFish.
Music Library Client
Prima di procedere con lo sviluppo del nostro java client dobbiamo specificare le dipendenze necessarie:
- 1️⃣ Progetto
MusicLibrary
: Properties ➡️ Libraries ➡️ Classpath ➕ ➡️ Add Projects... ➡️MusicLibrary
- 2️⃣ Libreria
gf-client.jar
: Properties ➡️ Libraries ➡️ Classpath ➕ ➡️ Add JAR/Folder ➡️[USER_HOME]/GlassFish_Server/glassfish/lib/gf-client.jar
, la libreria si trova nella vostra installazione di glassfish nel path specificato.
public class MusicLibraryClient {
public static void main(String[] args) throws NamingException {
Context ctx = new InitialContext();
MusicLibraryRemote ejb = (MusicLibraryRemote) ctx.lookup("java:global/MusicLibrary/MusicLibrary!it.pd2022.musiclibrary.MusicLibraryRemote");
List<Song> lista = ejb.findSongs();
for(Song s: lista)
System.out.println(s);
}
}
🚀 Il client della nostra applicazione è pronto possiamo eseguirlo. 🎯 Output:
run: nov 06, 2022 1:32:13 PM com.sun.enterprise.v3.server.CommonClassLoaderServiceImpl findDerbyClient INFORMAZIONI: Cannot find javadb client jar file, derby jdbc driver will not be available by default. Song{ID=2, authors=Home Free, name=Sea Shanty Medley, url=https://www.youtube.com/watch?v=lLGLUSzzuWU&ab_channel=HomeFree} Song{ID=1, authors=Queen, name=We Are The Champions, url=https://www.youtube.com/watch?v=KXw8CRapg7k&ab_channel=QueenVEVO} BUILD SUCCESSFUL (total time: 2 seconds)
Nota l'indirizzo JNDI dell'interfaccia remota del bean MusicLibrary può essere visualizzato nella console di output di glassfish subito dopo il deploy dell'applicazione.
Esercizio 2 - Music Library++ 🎵📚
Aggiungere le seguenti funzionalità al progetto MusicLibrary:
-
Ampliare la definzione di
Song
inserendo:- anno di rilascio,
- numero di visualizzazioni (numero di volte in cui il bravo è stato riprodotto),
- lyrics;
- specificare delle nuove NamedQuery che permettano la ricerca delle canzoni per anno di rilascio, nome autore, nome del brano.
-
Definire una nuova entità
Playlist
che consente di collezionare moltepliciSong
, specificando- nome,
- autore,
- tipologia,
- descrizione,
- data in cui è stato effettuato l'ultimo aggiornamento.
Le playlist possono essere create, modificate, visualizzate, ricercate per tipologia, ed eliminate senza eliminare dal database i brani contenuti.
-
Ampliare la definizione di
MusicLibrary
per supportare le precedenti nuove entità e funzionalità.- Introdurre la definizione di una metodo
play(song_ID)
che permette di ottenere la URL di una song, questo metodo va intercettato per aggiornare il numero di volte che un particolare brano viene riprodotto. Modificare il filebeans.xml
per aggiungere la definizione del nuovo interceptor:
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" version="1.1" bean-discovery-mode="all"> <interceptors> <class>org.agoncal.book.javaee7.chapter02.LoggingInterceptor</class> </interceptors> </beans>
- Opzionale: estendere la definizione del metodo play per la riproduzione di un lista di brani ottenuti da una particolare playlist.
- Introdurre la definizione di una metodo
Mofificare la classe main di MusicLibraryClient
per il testing e la verifica di tutte le funzionalità di MusicLibrary
.
Esercizio 3 - PDtify 🎵 ⏯️
Obiettivo: creare un enterprise java application con due moduli principali un modulo di business/persistenza e un modulo di presentazione web che permetta la gestione di una libreria musicale evoluta (playlist) utilizzando come player di riproduzione web le API di Youtube Embedded.
- ⚠️ prima di procedere effettuare l'undeploy del progetto precedente dal server glassfish.
PDtify
: New Project ➡️ Java with Ant ➡️ Java Enterprise ➡️ Enterprise Application- Output in Netbeans:
PDtify
enterprise application.PDtify-ejb
un modulo ejb.PDtify-web
un modulo web.
- Riportare il progetto
MusicLibray
nel moduloPDtify-ejb
. - Costruire un nuovo client web utilizzando una servelet
MusicPlayer
che sfrutta l'EJBMusicLibrary
per offrire attraverso una pagina web tutte le funzionalità dell'applicazione. Quando si crea la Servlet specificare Add information to the deployment descriptor (web.xml) passaggio 2 del wizard di creazione della Servlet. - Note:
- riportare nel modulo ejb tutte le definizione di persistence e beans.xml;
- quando si eseguono le operazioni di build, deploy, e run del progetto vanno lanciate dal progetto principale entrprise
PDtify
; - per specificare che di default la index della nostra applicazione sarà la Servlet
MusicPlayer
modificare il filePDtify-war/Web Pages/WEB-INF/web.xml
come segue:<servlet-mapping> <servlet-name>MusicPlayer</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
play()
la visualizzazione del metodo play può essere ottenuta utilizzando l'embedding della URL di un brano all'interno di un iframe:Song s = new Song("Queen","We Are The Champions", new URL("https://www.youtube.com/embed/KXw8CRapg7k")); out.println("<iframe width=\"420\""+ "height=\"315\"\n" + "src=\""+s.getUrl()+"\">\n" + "</iframe>");
Esercizi Bonus
Esercizio B.1 - Calcolatrice EJB
Scrivere un client Java che invoca degli EJB sul server che implementano un servizio di calcolatrice per tipi float. La calcolatrice offre tre metodi, tutti prendono in input due operandi di tipo float
e restituiscono un float
:
add(float,float)
sub(float,float)
multiply(float,float)
Il server offre inoltre un servizio di counting count()
che restituisce il numero di operazioni effettuate da tutti i clienti dall’avvio del server. Il client deve offrire da console un interfaccia che permetta di effettuare tutte le operazioni da remoto.
Esercizio B.2 - Calcolatrice EJB basata su stack
Scrivere un client Java che invoca degli Enterprise EJB sul server che implementano un servizio di calcolatrice basata su stack per tipi float
. La calcolatrice offre cinque metodi. Tre di questi metodi rappresentano operazioni aritmetiche che non prendono input e operano direttamente sui dati nello stack: add()
, sub()
, multiply()
.
In aggiunta, il server offre il metodovoid push(float)
e float pop()
per la gestione dello stack. Nota che l’unico metodo che restituisce valori è la pop()
. Le operazione aritmetiche eseguono implicitamente due pop()
per prelevare gli operandi e una push()
per salvare il valore di ritorno.
Esempio di esecuzione del servizio:
push(3)
,push(4)
,add()
,pop()
➡️ 7push(3)
,push(4)
,multiply()
,pop()
➡️ 12push(3)
,push(4)
,push(1)
,add()
,pop()
➡️ 5push(3)
,push(4)
,push(1)
,add()
,add()
,pop()
➡️ 8
Avanzato: gestire i meccanismi di attivazione e passivazione.
Esercizio B.3 - Calcolatrice EJB basata su stack persistente
Estendere il servizio di calcolatrice basata su stack implementata nell’esercizio precedente aggiungendo un livello di persistenza dello stack. In particolare, ad ogni operazione, lo stack deve essere salvato su database. All’interfaccia del servizio verrà aggiunto il metodo loadStack(String stackName)
e saveStack(String stackName)
che consentono all’utente di caricare lo stack da database . Se il client non invoca la loadStack()
, la sessione si avvia con uno stack vuoto. Lo stack puo essere salvato nel formato piu appropriato, anche come stringa.
Al fine di completare l’esercizo, occorre
- Implementare il metodo
loadStack(String username)
. - Implementare il metodo
saveStack(String username)
. - Implementare un metodo
stackList()
che restituisce tutti i nomi degli stack salvati su database. - Implementare un interceptor che, alla fine dell’interazione con un client, stampa una lista dei stackName usati da quell’utente in quella sessione.
Esercizio 0
- Riferimento: org.agoncal.book.javaee7.chapter13
- New Project ➡️ Java with Ant ➡️ Java Application
- Aggiungere le dipendenze:
Java EE7 API Library
egf-client.jar
-
Definire un nuovo wrapper per i messaggi relativi ad un ordine, come segue:
public class OrderDTO implements Serializable { private Long orderId; private Date creationDate; private String customerName; private Float totalAmount; public OrderDTO() { } public OrderDTO(Long orderId, Date creationDate, String customerName, Float totalAmount) { this.orderId = orderId; this.creationDate = creationDate; this.customerName = customerName; this.totalAmount = totalAmount; } //Getters and setters //toString() }
-
Definire un Producer di messaggi, come segue:
public class OrderProducer { public static void main(String[] args) throws NamingException { // Creates an orderDto with a total amount parameter float value = 10.0; Float totalAmount = Float.valueOf(10); OrderDTO order = new OrderDTO(1234l, new Date(), "Serge Gainsbourg", totalAmount); // Gets the JNDI context Context jndiContext = new InitialContext(); // Looks up the administered objects ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/javaee7/ConnectionFactory"); Destination topic = (Destination) jndiContext.lookup("jms/javaee7/Topic"); try (JMSContext jmsContext = connectionFactory.createContext()) { // Sends an object message to the topic jmsContext.createProducer().setProperty("orderAmount", totalAmount).send(topic, order); System.out.println("\nOrder sent : " + order.toString()); } } }
-
Definire un Consumer di messaggi, come segue:
public class OrderConsumer { public static void main(String[] args) throws NamingException { // Gets the JNDI context Context jndiContext = new InitialContext(); // Looks up the administered objects ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/javaee7/ConnectionFactory"); Destination topic = (Destination) jndiContext.lookup("jms/javaee7/Topic"); // Loops to receive the messages System.out.println("\nInfinite loop. Waiting for a message..."); try (JMSContext jmsContext = connectionFactory.createContext()) { while (true) { OrderDTO order = jmsContext.createConsumer(topic).receiveBody(OrderDTO.class); System.out.println("Order received: " + order); } } } }
🚀 A questo punto è possibile eseguire prima il Consumer e poi il Producer.
Esercizio 1
Scrivere un client Java che produce dei messaggi per un Topic di messaging su server Enterprise. Il client invia un messaggio con l’ordine per la costruzione di una moto, che è costituita da diverse componenti:
- Nome modello
- Nome telaio
- Nome pneumatici
Il server deve implementare attraverso un Message Driven Bean un servizio di notifica degli ordini, stampando a video il nome del modello della moto, del telaio e degli pneumatici. Il client deve offrire da console un’interfaccia che permetta di effettuare tutte le operazioni da remoto.
Note
- La ConnectionFactory deve chiamarsi:
jms/javaee7/ConnectionFactory
- Il Topic deve chiamarsi:
jms/javaee7/Topic
Esercizio 2
Estendere l’esercizio precedente attraverso l’implementazione di un servizio di persistenza degli ordini che salvi su una tabella del database tutti gli ordini arrivati al server. Aggiungere un Singleton che popoli il database con 2 ordini.
Note
- PersistentUnit e DB devono chiamarsi rispettivamente MotoPU e MotoDB
Esercizio 3
Estendere l’esercizio precedente aggiungendo un client Java che riceve i messaggi degli ordini delle moto e stampa li stampa a video; provare a ricevere tutti i messaggi inviati sul topic anche prima della sottoscrizione utilizzando un DurableConsumer.
try (JMSContext jmsContext = connectionFactory.createContext()) {
jmsContext.setClientID("uniqueID");
JMSConsumer topicSubscriber = jmsContext.createDurableConsumer((Topic) topic, "uniqueID");
OrderDTO order = topicSubscriber.receiveBody(OrderDTO.class);
System.out.println("Order received: " + order);
topicSubscriber.close();
}
Esercizio 4 - PDtify 🎵 ⏯️
Definire una nuova servlet Player
che si occupa di visualizzare il player youtube per un particolare brano o una playlist.
- Input: due parametri nel metodo GET
?id=x&type=song|playlist
:- song viene visualizzato a tutto schermo il player youtube;
- playlist vengono visualizzati tutti i brani in una tabella, e mostra un tasto play per ogni brano.
Quando la servlet viene caricata in modalità song viene inviato un nuovo messaggio sul Topic jsm/musicplayer/Player
(utilizzare la factory di default di installazione di glassfish) contenete l'identificativo del brano. Se la servlet viene caricata in modalità playlist si invia un messaggio sempre sullo stesso topic con l'identificativo della playlist.
La gestione dei messaggi avviene tramite l'utilizzo di MDB e degli eventi, per ogni messaggio si genera un messaggio di log visualizzato nella console di glassfish.
Sviluppare il progetto come segue:
-
Definire due nuovi Qualifier
SongEvent
ePlaylistEvent
. -
Definire un wrapper di messaggi
MessageWrapper
che permette di memorizzare l'id di un brano o di una playlist ed il relativo tipo di messaggio song/playlist. -
Definire un nuovo message-driven bean
MusicLibraryMDB
che implementaMessageListener
, per ogni messaggio ricevuto (MessageWrapper) si esegue il fire di un nuovo evento con body la relativa Song o Playlist. -
Definire due nuove classi
SongNotification
ePlaylistNotification
che definiscono un singolo metodonotify
che definisce un'opportuna@Observes
di un entitàSong
oPlaylist
(parametro del metodo) con l'obiettivo di visualizzare un messaggio di log.public class PlaySongNotification { public void notify(@Observes Song s){ System.out.println("Playing song "+s.getName()); } }
-
Definire un nuovo stateless EJB
EventProducer
che consente di inviare messaggi su Topicjsm/musicplayer/Player
. -
Definire una nuova servlet
Player
che si comporta come descritto ed utilizza l'EventProducer
per notificare il play di un brano. -
Definire un client Java
MDBtest
nel package test del ptrogetto EJB che definire un metodo main nel quale si esegue il test di tutte le funzionalità di scambio di messaggi definiti (aggiungere il file gf-client.jar come dipendenza). -
Modificare la servlet
MusicPlayer
al fine di utilizzare la nuova servletPlayer
per effettuare il play di un brano o una playlist.
Contenuti
Parte 1
- Service-Oriented Architecture
- I Web Services
- Definizioni
- I ruoli nei WS
- Gli standard
- WSDL
- SOAP
- UDDI
- Le specifiche di WS
Parte 2
- WS in Java
- WSDL Mapping
- Eccezioni e Fault
- Contesto e ciclo di vita
- Un esempio riassuntivo
- Supporto ai WS in Netbeans
- il progetto per WS
- testing
- WS Client
Materiale bibliografico
- "Beginning Java Enterprise Edition": capitolo 14
- "A Survey of Web Services Technologies". Papazoglou, Michael P. and Dubray, Jean-jacques (2004)
Domande di riepilogo
- Che cos'e' una Service-Oriented Architecture?
- Quali sono i requisiti di un Web Service?
- Il ruolo del proxy nel meccanismo di invocazione di un Web Service
- Cosa rappresenta il file WSDL?
- Che cos'e' SOAP?
- Quali sono le gli stili di SOAP binding?
- Quando UDDI risulta opzionale?
- Come vengono gestite le eccezioni nei WS?
- Come si scrive un WebService in Java?
- A cosa servono le annotazioni @WebMethod, @WebResult, @WebParam?
- Quali sono le differenze tra la serializzazione classiche e quella di JAXB?
- A cosa servere avere un WebService come EJB Stateless?
Contenuti
Parte 1
- Service-Oriented Architecture
- I Web Services
- Definizioni
- I ruoli nei WS
- Gli standard
- WSDL
- SOAP
- UDDI
- Le specifiche di WS
Parte 2
- WS in Java
- WSDL Mapping
- Eccezioni e Fault
- Contesto e ciclo di vita
- Un esempio riassuntivo
- Supporto ai WS in Netbeans
- il progetto per WS
- testing
- WS Client
Materiale bibliografico
- "Beginning Java Enterprise Edition": capitolo 14
- "A Survey of Web Services Technologies". Papazoglou, Michael P. and Dubray, Jean-jacques (2004)
Domande di riepilogo
- Che cos'e' una Service-Oriented Architecture?
- Quali sono i requisiti di un Web Service?
- Il ruolo del proxy nel meccanismo di invocazione di un Web Service
- Cosa rappresenta il file WSDL?
- Che cos'e' SOAP?
- Quali sono le gli stili di SOAP binding?
- Quando UDDI risulta opzionale?
- Come vengono gestite le eccezioni nei WS?
- Come si scrive un WebService in Java?
- A cosa servono le annotazioni @WebMethod, @WebResult, @WebParam?
- Quali sono le differenze tra la serializzazione classiche e quella di JAXB?
- A cosa servere avere un WebService come EJB Stateless?
- Esercizio 0 - Card Validator
- Esercizio 1 - Previsioni Meteo
- Esercizio 2 - Web Service Previsioni Meteo Avanzate
- Esercizio 3 - PDtify 🎵 ⏯️
Esercizio 0 - Card Validator
-
New project ➡️ Java with Ant ➡️ Java Web ➡️ Web Application:
CardValidatorWebApplication
-
Definiamo un nuovo oggetto
Card
utilizzando JAXB (Java Architecture for XML Binding)@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class CreditCard { @XmlAttribute(required = true) private String number; private String expiryDate; private Integer controlNumber; private String type; // Constructors , getters , setters }
-
Definiamo una nuova interfaccia
Validator
@WebService public interface Validator { public boolean validate(CreditCard creditCard); }
-
Definiamo un nuovo Web Service
CardValidator
che implementa un interfacciaValidator
- New Files ... ➡️ Web Services ➡️ Web Service
- Name :
CardValidator
- Implement Web Service as Stateless Session Beans: [✔️]
@WebService(serviceName = "CardValidator")
public class CardValidator implements Validator {
public boolean validate(CreditCard creditCard) {
Character lastDigit = creditCard.getNumber().charAt( creditCard.getNumber().length() - 1);
if (Integer.parseInt(lastDigit.toString()) % 2 == 0) {
return true;
} else {
return false;
}
}
}
- Testing: Project ➡️ Web Services ➡️
Card Validator
➡️ Test Web Service - Aggiungere al Web Service
Card Validator
un nuovo metodovalidatedata
che prende come parametri tutti i campi diCard
singolarmente e utilizzavalidate
restituire una stringavalid| not valid
.- utilizzare il wizard di netbeans per aggungere il metodo Project ➡️ Web Services ➡️
Card Validator
➡️ Add Operation ... - successivamente modificare il codice come segue:
public String validatedata(String number, String expiryDate, Integer controlNumber, String type) { Character lastDigit = number.charAt( number.length() - 1); if (validate(new CreditCard(number, expiryDate, controlNumber,type))) { return "valid"; } else { return "not valid"; } }
- utilizzare il wizard di netbeans per aggungere il metodo Project ➡️ Web Services ➡️
- Definire un nuovo Web Service Client
- New Project ➡️ Jav with Ant ➡️ Java Application
- Nome:
ValidateWSClient
- Project ➡️ New Web Service Client
- Project ➡️ Browse ...
CardValidatorWebApplication
➡️CardValidator
- Visualizzare i file generati in
Generated Sources (jax-ws)
- Definire l'oggetto
ValidateWSClient
come segue:public class ValidateWSClient { public static void main(String[] args) { CardValidator_Service service = new CardValidator_Service(); CardValidator port = service.getCardValidatorPort(); CreditCard card = new CreditCard(); card.setNumber("6011111111111118"); System.out.println(port.validate(card)); } }
Esercizio 1 - Previsioni Meteo
Scrivere un servizio Web Service che implementa un servizio di previsioni meteo. Il servizio
implementa un servizio forecast()
che prende in input una stringa con il nome del luogo
in cui fare previsione (ad esempio “Salerno” o “Fisciano”), e restituisce una stringa con la
previsione (ad esempio “sole”, “pioggia”, “neve”, “nebbia”). L’implementazione del servizio
restituisce sempre “sole” se l’input è “Salerno”, “pioggia” se l’input è “Fisciano”, oppure un
valore casuale se l’input è diverso.
Implementare un client Java che richiede il servizio di previsioni per diverse località, e le stampa a video.
Esercizio 2 - Web Service Previsioni Meteo Avanzate
Aggiungere al Web Service dell’esercizio precedente una funzionalità chiamata
advancedForecast()
che prende in input un oggetto Place
con i seguenti attributi:
- Stringa con nome del posto
- Coordinate GPS
e restituisce un oggetto Forecast con i seguenti attributi:
- Stringa con la descrizione della previsione
- Temperatura
- Direzione del vento
- Forza del vento
- Umidità
I valori in output posso essere casuali. Implementare un client Java che richiede il servizio di previsioni avanzato per diverse località, e le visualizza su standard output.
Esercizio 3 - PDtify 🎵 ⏯️
Modificare il progetto PDtify per offrire le funzionalità di MusicLibrary utilizzando anche un Web Service. Sviluppare un client java che permette di eseguire tutte le funzionalità di PDtify e per eseguire il play di una canzone utilizzare il seguente esempio.
public class TestOpenBrowser {
public static void main(String[] args) {
String url = "https://www.youtube.com/embed/lLGLUSzzuWU";
if(Desktop.isDesktopSupported()){
Desktop desktop = Desktop.getDesktop();
try {
desktop.browse(new URI(url));
} catch (IOException | URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("xdg-open " + url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}