PROGRAMMAZIONE DISTRIBUITA

Università degli Studi di Salerno

Libri di testo

Materiale

🗓️LezioneMaterialeRiferimenti
06/10/2023Java Socket TCP 1📕Cap. 2
09/10/2023Java Socket TCP 2Installazione ambiente di sviluppo (solo prima sezione)📕 Cap. 2
12/10/2023RMI 1RMI 1 - Hello World📕 Cap. 3
13/10/2023RMI 2📕 Cap. 4
16/10/2023Laboratorio Java RMIRMI - Esercizi Java RMI
Fine Parte A
19/10/2023Introduzione Java Enterprise Edition (Java EE)Java EE📗 Cap. 1
20/10/2023Contexts and Dependency Injection (CDI)CDI Part 1📗 Cap. 2
23/10/2023Laboratorio Starting with J2EEJ2EE Lab
26/10/2023CDI InterceptorCDI Part 2📗 Cap. 2
27/10/2023Java Persistence API (JPA) JPA - Part 1📗 Cap. 4-5
30/10/2023Java Persistence API (JPA) JPA - Part 2 Laboratorio JPA📗 Cap. 4-5
02/11/2023Enterprise JavaBeans (EJB) - Part 1 EJB - Part 1📗 Cap. 7-9
06/11/2023EJB - Part 2 ➕ Laboratorio EJB (Esercizio 0) EJB - Part 2 EJB - Lab📗 Cap. 7-9
09/11/2023Java Message Service (JMS) - Part 1 ➕ 📝 Quiz Parte A JMS - Part 1📗 Cap. 13
10/11/2023JMS - Part 2 JMS - Part 2📗 Cap. 13
Fine Parte B
13/11/2023Laboratorio EJB ➕ JMSEJB - Lab JMS - Lab
16/11/2023Java Web Services (WS) Parte 1Java Web Services (WS) Parte 1📗 Cap. 14
17/11/2023Java WS Parte 2Java WS Parte 2📗 Cap. 14
Fine Parte C
20/11/2023Laboratorio Java WS ➕ 📝 Quiz Parte BLaboratorio Java WS
23/11/2023Introduzione al Cloud ComputingMateriale cloud computing
24/11/2023Laboratorio J2EE Step-by-step
27/11/2023Laboratorio J2EE Step-by-step
30/11/2023Laboratorio J2EE Step-by-step
01/12/2023Laboratorio J2EE Step-by-step
04/12/2023From J2EE to Spring Framework (Teoria)Introduzione a Spring Framework
07/12/2023From J2EE to Spring Framework (Pratica)Spring Framework In Action
11/12/2023Laboratorio J2EE Step-by-step
15/12/2023Laboratorio J2EE Step-by-step
18/12/2023📝 Parte C

Informazioni modalità d'esame

Prova scritta ➡️ Svolgimento prova a casa ➡️ Consegna progetto ➡️ Prova orale

Prova scritta

Date (da verificare su ESSE3)

🗓️🕘📍
16/01/202315:00-17:30P3/P4
31/01/202315:00-17:30F1/F8
16/02/202315:00-17:30P3/P4

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

📝 Esame: modalità con prove intercorso per studenti corsisti

E-Learning UNISA PD 23/24

L'esame per gli studenti corsisti può essere sostenuto tramite 3 prove intercorso + 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 A20% Quiz Parte B60% Programma JEEVoto di accesso esame orale
18181818
18301820,4
18183025,2
003018
3030012
0303024
30006

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:45F8
Quiz Parte B (Fino a JMS)20/11/2023 14:45-15:15Lab Sammet
Programma JEE18/12/2023 14:30-17:00Lab 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-a-2023

Quiz Parte B

quiz-b-2023

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 directory bin della jdk,
    • per permettere al registro di caricare la codebase necessaria dobbiamo avviarlo all'interno della directory contente i file .classdel nostro progetto, nel costro caso la direcory $Project/build/classes
  • 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
  1. Definizione interfaccia remota Hello.java
   public interface Hello extends java.rmi.Remote {
     String dimmiQualcosa(String daChi) throws java.rmi.RemoteException;
   }
  1. 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 { 
        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();
        }
    }
}
  1. 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(); }

    }
}
  1. Esecuzione del progetto
    • avviare rmiregistry dalla directory ~/$PROJECT_NAME/build/classes porta di default rmiregistry 1099.
    • eseguire HelloImpl.javada netbeans tasto destro run file.
    • eseguire HelloClient.javada netbeans tasto destro run file.

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

  1. 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'interfaccia Calculator ed estende java.rmi.server.UnicastRemoteObject definendo la logica dell'applicazione;
    • CalculatorServer definisce solo il metodo main e costruisce ed esporta l'oggetto remoto CalculatorImpl;
    • CalculatorClient utilizza l'oggetto remoto Calculator.
  2. 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.

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 directory bin della jdk,
    • per permettere al registro di caricare la codebase necessaria dobbiamo avviarlo all'interno della directory contente i file .classdel nostro progetto, nel costro caso la direcory $Project/build/classes
  • 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
  1. Definizione interfaccia remota Hello.java
   public interface Hello extends java.rmi.Remote {
     String dimmiQualcosa(String daChi) throws java.rmi.RemoteException;
   }
  1. 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 { 
        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();
        }
    }
}
  1. 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(); }

    }
}
  1. Esecuzione del progetto
    • avviare rmiregistry dalla directory ~/$PROJECT_NAME/build/classes porta di default rmiregistry 1099.
    • eseguire HelloImpl.javada netbeans tasto destro run file.
    • eseguire HelloClient.javada netbeans tasto destro run file.

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

  1. 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'interfaccia Calculator ed estende java.rmi.server.UnicastRemoteObject definendo la logica dell'applicazione;
    • CalculatorServer definisce solo il metodo main e costruisce ed esporta l'oggetto remoto CalculatorImpl;
    • CalculatorClient utilizza l'oggetto remoto Calculator.
  2. 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.

Introduzione Java Enterprise Edition (Java EE)

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

Altri link interessanti

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)

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

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

  1. Code ➡️ Download Zip, Unarchive the project zip, Open Project
  2. Aprire il progetto chapter02-samples
  • Aggiungere nel descrittore di progetto Maven nella dipendenza javaee-apila versione specifica di J2EE 7.0
    <dependency>
      <groupId>javax</groupId>
      <artifactId>javaee-api</artifactId>
      <version>7.0</version>
    </dependency> 
  • Analizzare il codice degli esercizi
  1. 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 package org.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 file Web Pages/WEB-INF/beans.xml se non presente crearlo con new file in Web 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 @Injectper includere una nuova istanza BookServicenel 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 il testo hello world. La stringa viene elaborata tramite un particolare POJO MB che implementa l'interfaccia Letters è possibile utilizzare Injection, Qualifiers, e Producers.

  • Ad es. provare a definire un producer per la stringa hello world e un producer per la stringa HELLO WORLD in maiuscolo specificando due diversi qualifiers per i due producer, e alternare l'utilizzo dei due producer nella servlet per visualizzare il testo in minuscolo e maiuscolo in richieste diverse.

2. ⏯️ Esercizio Music Library primi 👣

Gestire una libreria musicale definendo un oggetto POJO Song e un oggetto Library che è un POJO 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;
  • e di gestire tutte le successive operazioni possibili in una libreria inizializzata con un produces (aggiungi, cancella, trova per ID, trova per nome, etc.).
  • Opzionale: realizzare una serverlet che permette di visualizzare il contenuto della libreria in una pagina HTML, e di aggiungere nuove canzoni tramite un form HTML.

3. Verifica del funzionamento di Safe Exam Browser

Approfondimenti

Contexts and Dependency Injection (CDI)

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

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

  1. Da Derby, creare il database con un utente associato. Fate attenzione a specificare user name e password non vuote.
  2. Creare una classe Entity Book caratterizzata da:
    • titolo, prezzo, descrizione, isbn e categoria.
  3. 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

🚀 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 remota HelloWorldRemote.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 ìt.pd2023.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.xmlche 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"
  • A questo punto possiamo completare il nostro DatabasePopulator.javainserendo 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:

  1. 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.
  2. Definire una nuova entità Playlist che consente di collezionare molteplici Song, 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.

  3. 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 file beans.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.

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 modulo PDtify-ejb.
  • Costruire un nuovo client web utilizzando una servelet MusicPlayer che sfrutta l'EJB MusicLibrary 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 file PDtify-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() ➡️ 7
  • push(3), push(4), multiply(), pop() ➡️ 12
  • push(3), push(4), push(1), add(), pop() ➡️ 5
  • push(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

  1. Implementare il metodo loadStack(String username).
  2. Implementare il metodo saveStack(String username).
  3. Implementare un metodo stackList() che restituisce tutti i nomi degli stack salvati su database.
  4. 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

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

🚀 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 remota HelloWorldRemote.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 ìt.pd2023.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.xmlche 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"
  • A questo punto possiamo completare il nostro DatabasePopulator.javainserendo 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:

  1. 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.
  2. Definire una nuova entità Playlist che consente di collezionare molteplici Song, 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.

  3. 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 file beans.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.

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 modulo PDtify-ejb.
  • Costruire un nuovo client web utilizzando una servelet MusicPlayer che sfrutta l'EJB MusicLibrary 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 file PDtify-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() ➡️ 7
  • push(3), push(4), multiply(), pop() ➡️ 12
  • push(3), push(4), push(1), add(), pop() ➡️ 5
  • push(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

  1. Implementare il metodo loadStack(String username).
  2. Implementare il metodo saveStack(String username).
  3. Implementare un metodo stackList() che restituisce tutti i nomi degli stack salvati su database.
  4. 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 e gf-client.jar
  1. 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()
    }
    
  2. 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());
        }
     }
    }
    
  3. 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 e PlaylistEvent.

  • 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 implementa MessageListener, per ogni messaggio ricevuto (MessageWrapper) si esegue il fire di un nuovo evento con body la relativa Song o Playlist.

  • Definire due nuove classi SongNotificatione PlaylistNotification che definiscono un singolo metodo notify che definisce un'opportuna @Observes di un entità Song o Playlist (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 Topic jsm/musicplayer/Player.

  • Definire una nuova servlet Playerche 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 servlet Playerper 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

  • 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 interfaccia Validator

    • 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 metodo validatedatache prende come parametri tutti i campi di Cardsingolarmente e utilizza validate restituire una stringa valid| 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"; 
                  }
      }    
      
  • 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();
            }
        }
    }
    
}