Appunti integrativi TPSI5 2017-2018

Vai all’indice

Appunti integrativi di Tecnologie di progettazione di sistemi informatici e di telecomunicazione

Classe 5a a.s. 2017/2018

Maria Grazia Maffucci

Giuliano Bellucci

ottobre 2017 - maggio 2018

                                   

This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/.

Contact mariagrazia@maffucci.cc


Indice

Programmazione per la comunicazione in rete usando i socket        7

A1 Tecnologie e protocolli delle reti di computer        8

A5 Socket programming in linguaggio Java        8

Protocolli applicativi di rete        8

Protocollo        8

Livello delle applicazioni        8

Interfacce e servizi        8

Punti di accesso        8

Implementazione del servizio        9

Tipi di servizi        9

Protocol Data Unit        9

Progettazione di un protocollo        9

Indirizzamento        10

Frammentazione e riassemblaggio        10

Incapsulamento        10

Controllo della connessione        11

Fasi di una connessione        11

Servizio confermato o non confermato        11

Controllo degli errori        11

Controllo del flusso        12

Multiplexing e demultiplexing        12

Servizi di trasmissione        12

Esempi di protocolli applicativi di rete        12

Protocolli applicativi di rete esistenti        12

Protocolli applicativi di rete implementabili        13

Esempi di protocolli applicativi di rete implementabili        14

CLIL Writing and Speaking - Networking, TCP  and UDP  protocols        15

CLIL Writing and Speaking - Java sockets        15

I sistemi distribuiti: modelli architetturali hardware e software        16

I sistemi distribuiti        17

Caratteristiche dei sistemi distribuiti        18

Affidabilità        18

Integrazione        19

Trasparenza        20

Economicità        21

Complessità        21

Storia dei sistemi distribuiti e modelli architetturali        22

CLIL Listening and Speaking - Quantum Computers        22

Architetture distribuite hardware        23

SISD        23

SIMD        23

MISD        24

MIMD        24

MIMD a memoria fisica condivisa        25

MIMD a memoria fisica distribuita        26

Cluster di PC        26

CLIL Listening and Speaking - Flynn Taxonomy and Cluster Architecture        27

Architetture distribuite software        27

Architettura centralizzata        27

Architettura client-server        28

Architettura multi-tier        29

CLIL Listening and Speaking - n-Tier Architecture        30

Middleware        31

CLIL Listening and Speaking - Middleware        32

Java e XML        33

A6 Gestione dei documenti in formato XML        34

Esempi di parsing di un documento XML con DOM        34

Esempio 1        34

Esempio 2        39

Esempio 3        42

HTTP e Servlet        46

A8 Realizzazione di web-service di tipo REST in linguaggio Java        47

CLIL Reading - What is a servlet and HTTP        47

GET request        47

POST request        49

HTTP status code        50

CLIL Reading - Servlet        50

Esercizi sulle Servlet        51

Web Service REST        59

A7 Web-service di tipo REST: interazione con linguaggio Java        60

Ragioni dell’uso dei Web service        60

Integrazione        60

Usabilità        60

Interoperabilità        60

Accoppiamento debole (loosely coupled)        60

Deployability        61

A8 Realizzazione di web-service di tipo REST in linguaggio Java        61

I principi dell’architettura RESTful        61

CLIL Listening and Writing- Introduction to Web Services REST        62

Identificazione delle risorse        62

CLIL Listening and Writing - REST and HTTP        63

CLIL Listening and Writing - Resource URIs        63

CLIL Listening and Writing - Collection URIs        64

Utilizzo esplicito dei metodi HTTP        64

CLIL Listening and Writing - HTTP Methods        66

Idempotenza dei metodi HTTP        66

CLIL Listening and Writing - Method Idempotence        67

Risorse autodescrittive        67

CLIL Listening and Writing - REST Response        68

Collegamenti tra risorse e il principio HATEOAS        68

CLIL Listening and Writing - HATEOAS        71

Comunicazione senza stato        71

Stato delle risorse e dell’applicazione        72

CLIL Listening - The Richardson Maturity Model        73

CLIL Listening - Developing RESTful APIs with JAX-RS        74

REST e sicurezza HTTP (cenni)        75

Sicurezza con “sessioni REST” e tramite servizi di terze parti (cenni)        76

Lo stato come risorsa        76

OpenID e OAuth: gestione esterna della sicurezza        77

Esempi di Web service di tipo REST in linguaggio Java        78

Calcolatrice REST        78

Web service per operazioni CRUD su database        84

JDBC e MySQL        84

ShowRoom REST su database        84

Database EsempioREST        87

Server di connessione al database EsempioREST        95

Web service REST SimpleRestDb        110

Client RestClient        121

Esercizi        124

Esercizi sui protocolli di comunicazione        124

Socket TCP        124

Socket UDP        126

Aspetti progettuali di un protocollo di comunicazione        127

Esercizi su XML, Java parser e Web service        129

XML        129

Java parser        132

Esercizi di progettazione di architetture distribuite        133

Voli low cost        133

MyShow        134

Realizzazione        136

Sviluppi futuri        136

Centro assistenza        136

Realizzazione        138

GTT (trasporre)        139

Dottorato (trasporre)        140

Olimpiadi (trasporre)        141

Grande Fratello (trasporre)        142

UVI (trasporre)        143

Bibliografia e sitografia        144

I socket e la comunicazione in rete        144

I sistemi distribuiti: modelli architetturali hardware e software        144

Java e XML        146

HTTP e Servlet        146

Web Service REST        147


Programmazione per la comunicazione in rete usando i socket


A1 Tecnologie e protocolli delle reti di computer

STUDIARE: G. Meini, F. Formichi, Tecnologie di progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2017, pp.2-39.

A5 Socket programming in linguaggio Java

STUDIARE: G. Meini, F. Formichi, Tecnologie di progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2017, pp.94-140.

Protocolli applicativi di rete

Protocollo

E’ l’insieme di regole utilizzate da due entità per scambiarsi informazioni, specificando cosa deve essere comunicato, in che modo e quando.

Degli esempi di protocolli sono quelli utilizzati nell’architettura di rete a strati TCP/IP.

Livello delle applicazioni

La pila protocollare TCP/IP si occupa di fornire i servizi associati ad ogni applicazione di rete, come ad es. SMTP, FTP, HTTP, ecc.

Il livello delle applicazioni supporta diverse applicazioni e, per ognuna di esse offre determinati servizi.

Se il servizio è di tipo client-server il protocollo dovrà prevedere sempre la gestione di queste due diverse entità e delle relative comunicazioni. Ciò vuol dire che i processi dovranno essere almeno due, il client e il server.

Interfacce e servizi

Nella pila protocollare TCP/IP la comunicazione avviene tra strati adiacenti tramite una interfaccia che definisce quali servizi offrire allo strato inferiore e quali sono le operazioni corrispondenti che lo strato inferiore può invocare per ottenere il servizio.

Punti di accesso

I servizi offerti da uno strato sono disponibili presso un SAP (Service Access Point) che identifica il punto di accesso (lo “sportello”) dove è disponibile il servizio, e generalmente viene implementato come una coda di messaggi. Ogni SAP ha un indirizzo univoco che deve essere specificato dall’utente per richiedere il servizio.

Implementazione del servizio

L’utente invia una IDU (Interface Date Unit) al SAP contenente informazioni di controllo e dati.

Il livello protocollare preleva una IDU dal SAP ed esegue la corrispondente primitiva del servizio creando una o più PDU (Protocol Data Unit) da inviare ai suoi pari. Il livello protocollare per trasmettere i PDU richiederà un servizio al livello sottostante.

Tipi di servizi

  • Orientati alla connessione: il protocollo prevede delle istruzioni che permettano di creare una connessione fra gli estremi della comunicazione; i dati sono consegnati in ordine ai pari e se persi vengono ritrasmessi. Di solito è previsto anche un riscontro della ricezione in modo da prevedere un metodo di ritrasmissione dei dati nel caso venissero persi.
  • Senza connessione: i dati non vengono consegnati in ordine ai pari e può o meno esserci il riscontro della ricezione. Di conseguenza, nel caso non ci sia il riscontro della ricezione, i dati persi non saranno gestiti in alcun modo.

Protocol Data Unit

Ogni protocollo prevede lo scambio di pacchetti denominati in modo generale PDU (Protocol Data Unit). Di solito un PDU conterrà:

  • una intestazione o header (dati di controllo aggiunti dal protocollo);
  • corpo o body (dati utente);
  • coda o tail (i trailer, o footer) (dati di controllo aggiunti dal protocollo).

Lo header e il tail sono usati dal protocollo per controllare la comunicazione, ad esempio, lo header contiene informazioni utilizzate dall’entità del protocollo come:

  • indirizzo del sistema e del SAP di destinazione;
  • numero di sequenza (per poter ordinare le PDU);
  • codice per la individuazione di errori di trasmissione;
  • codice identificativo di servizi particolari (es. priorità).

Progettazione di un protocollo

Ogni protocollo deve definire le regole per gestire i seguenti aspetti (non necessariamente un protocollo deve gestirli tutti):

  1. indirizzamento;
  2. frammentazione e riassemblaggio;
  3. incapsulamento;
  4. controllo della connessione;
  5. servizio confermato o non confermato;
  6. controllo degli errori;
  7. controllo del flusso;
  8. multiplexing;
  9. servizi di trasmissione.

Indirizzamento

L’indirizzamento permette di identificare univocamente una entità nella rete. Esistono diversi livelli di indirizzamento e ogni livello ha una propria visibilità:

  • indirizzo fisico (locale a una rete): indirizzo MAC;
  • indirizzo di rete (globale sull’interrete): indirizzo IP (TCP/IP) o Network Service Access Point (OSI);
  • indirizzo del processo (locale al sistema): numero di porta (TCP/IP) o Service Access Point (OSI).

Gli indirizzi assegnati agli host o ai processi possono essere di tipo unicast, multicast o broadcast. Diversamente si possono creare circuiti virtuali usando degli identificatori assegnati alla connessione, che permettono di ridurre l’overhead di comunicazione e stabiliscono un instradamento fissato per la connessione.

Frammentazione e riassemblaggio

La frammentazione divide un messaggio in blocchi di dimensione fissata e ogni blocco sarà inserito in un particolare PDU. Se viene prevista questa fase nel protocollo dovrà essere necessariamente prevista anche la fase di riassemblaggio per riottenere il dato originale.

Vantaggi:

  • controllo degli errori su ogni blocco;
  • utilizzo equo del mezzo trasmissivo;
  • in caso di errori si potrà ritrasmettere un solo blocco;
  • minori ritardi;
  • buffering di dimensione ridotte.

Svantaggi:

  • maggiore elaborazione;
  • minore quantità di dati trasmessi nell'unità di tempo vista la maggiore elaborazione richiesta (minor throughput).

Incapsulamento

Definisce quali informazioni di controllo devono essere aggiunte ai dati e come vengono organizzate all’interno di un PDU, ad es. indirizzi, controllo degli errori, controlli del protocollo. Tramite il processo di incapsulamento viene aggiunto uno header ed eventualmente un tail affinché l’entità protocollare paritaria possa capire come gestire il payload (dati) del PDU.

Controllo della connessione

Se il protocollo non è orientato alla connessione (connectionless) questa fase non è prevista.

Se il protocollo è invece orientato alla connessione (connection-oriented) deve prevedere le seguenti fasi:

  1. creare la connessione;
  2. trasmettere i dati;
  3. chiudere la connessione.
Fasi di una connessione
  1. Nella fase di creazione della connessione le entità si accordano su come scambiarsi i dati:
  1. caso semplice: il mittente fa una richiesta di connessione e il ricevente accetta o rifiuta;
  2. caso complesso: oltre alla instaurazione di una connessione, le due entità prevedono una fase di negoziazione per garantire un determinato livello del servizio di trasmissione (priorità, quality of service, sicurezza).
  1. Nella fase di trasferimento dei dati si dovranno prevedere tutti o solo parte dei seguenti controlli:
  1. corretta sequenza dei blocchi di dati prevedendo ad esempio nello header un codice che permetta di ricostruire il dato originale indipendentemente dall’ordine di arrivo dei PDU;
  2. controllo degli errori, ad esempio utilizzando un CRC;
  3. controllo del flusso, ad esempio prevedendo un limite massimo di PDU che possono essere trasmessi per motivi di bufferizzazione.
  1. Nella fase di chiusura della connessione le due entità concordano di terminare la comunicazione.

Servizio confermato o non confermato

Il protocollo può essere affidabile prevedendo una tecnica di conferma dei PDU ricevuti oppure può non essere affidabile se non prevede tale conferma. Le modalità di conferma possono essere molto semplici come la conferma di ogni singolo PDU appena questo viene ricevuto, oppure prevedere tecniche più raffinate come la conferma cumulativa adottata dal protocollo TCP.

Controllo degli errori

Il controllo degli errori serve ad individuare eventuali alterazioni dei dati o delle informazioni di controllo. Può essere implementato in due fasi, prevedendo inizialmente l’individuazione degli errori e poi la ritrasmissione dei dati. A volte vengono usati dei codici che riescono ad individuare e correggere automaticamente gli errori.

Controllo del flusso

Il controllo del flusso è utilizzato dal ricevente per limitare la velocità con cui la sorgente gli invia i dati. Infatti la sorgente non deve inviare più dati di quanti il ricevente possa riceverne.

Multiplexing e demultiplexing

Per multiplexing si intende la corrispondenza di più connessioni ad un determnato livello protocollare, che confluiscono in una sola connessione al livello inferiore. Il multiplexing consente di aggregare i dati e di ottimizzare l’efficienza della trasmissione.

Il ricevente dovrà necessariamente implementare un meccanismo di disaggregazione (demultiplexing) dei dati per consegnare i dati al corretto destinatario.

400px-Telephony_multiplexer_system.gif

Servizi di trasmissione

Se la trasmissione richiede determinati livelli di servizi, questi dovranno essere negoziati nella fase di creazione della connessione (caso complesso). I servizi di trasmissione possono prevedere:

  • priorità: precedenza ai messaggi di controllo o di determinati utenti;
  • quality of service: minimo ritardo accettabile, minimo throughput accettabile;
  • sicurezza: restrizioni di accesso.

Esempi di protocolli applicativi di rete

I protocolli applicativi di rete consentono la comunicazione tra processi utente su sistemi diversi e forniscono diversi servizi di comunicazione

Protocolli applicativi di rete esistenti

Di seguito sono elencati alcuni protocolli applicativi di rete comunemente usati su Internet:

  • TELNET: terminale remoto;
  • FTP: trasferimento di file;
  • SMTP: posta elettronica;
  • HTTP: trasferimento di dati ipertestuali;
  • BGP: protocollo di gestione del routing fra autonomous system diversi;
  • SNMP: protocollo che consente la configurazione, la gestione e la supervisione di apparati collegati in una rete (dispositivi di rete o terminali utente), riguardo a tutti gli aspetti che richiedono azioni di tipo amministrativo;
  • DNS: protocollo per la risoluzione dei nomi di dominio utilizzando un database distribuito;
  • DHCP: protocollo che permette ai dispositivi di una rete locale di ricevere automaticamente, ad ogni richiesta di accesso ad una LAN IP, la configurazione IP necessaria per stabilire una connessione;
  • SSH: protocollo che utilizza tecniche crittografiche per effettuare operazioni di rete in modo sicuro su una rete non sicura;
  • NTP: protocollo usato pe la sincronizzazione degli orologi tra sistemi di computer;
  • POP: protocollo per il recupero delle e-mail di un client depositate in un server remoto;
  • IMAP: protocollo per il recupero delle e-mail di un client depositate in un server remoto;
  • SFTP: protocollo per il trasferimento non sicuro di file, con un livello di complessità intermedio tra TFTP e FTP;
  • TFTP: protocollo di trasferimento file molto semplice, che veniva utilizzato ad es. per l’avvio di computer che non hanno dispositivi di memoria di massa, come i router;
  • ECHO: protocollo originariamente proposto per testare e misurare il round-trip times nelle reti IP.
  • DAYTIME: protocollo di spedizione della data e dell’ora fornita da un server;
  • TIME: protocollo di spedizione della data e dell’ora fornita da un server come numero di secondi a partire da 1 gennaio 1900;
  • DISCARD: protocollo che butta via qualsiasi dato riceva;
  • CHARACTER GENERATOR: protocollo che genera e invia dati indipendentemente dall’input;
  • QOTD: protocollo che invia un breve messaggio (Quote Of The Day);
  • MESSAGE SEND PROTOCOL: protocollo per l’invio di brevi messaggi fra nodi di una rete;
  • WHOIS: protocollo per il recupero delle informazioni di utenti Internet.

Protocolli applicativi di rete implementabili

Oltre ai normali protocolli applicativi di rete già standardizzati, è possibile crearne dei propri, come ad esempio:

  • SOMMA: il protocollo prevede che un client invii due valori numerici al server il quale ne determinerà la somma e la invierà al client;
  • CALCOLATRICE: protocollo che prevede l’invio da parte di un client di due valori numerici e di un operatore aritmetico, la ricezione da parte del server dei valori e dell’operatore e il relativo calcolo e, la spedizione al client del risultato;
  • CHAT: protocollo che permette di implementare una semplice chat unicast.
  • CONVERTI: protocollo che prevede l’invio da parte di un client di una stringa e il server la convertirà in maiuscolo rispedendogliela;
  • SPAM: protocollo che preveda lo spam di una frase inviata da un client a tutti i client connessi al server che la riceve.

Esempi di protocolli applicativi di rete implementabili

Esempi di descrizioni di protocolli applicativi di rete li potrete trovare nelle seguenti specifiche di progetto per l’avvio della relativa progettazione:


CLIL Writing and Speaking - Networking, TCP  and UDP  protocols

Answer to the following questions.

  1. What is an IP address?
  2. Which is the purpose of a netmask?
  3. What is the main purpose of the Transport Protocol?
  4. What are the main characteristics of UDP?
  5. What are the main characteristics of TCP?
  6. What is a port in the Transport Protocol?
  7. What kind of applications use TCP?
  8. What kind of applications use UDP?
  9. What is a protocol?
  10. Which data unit is transferred by UDP?
  11. Which data unit is transferred by TCP?
  12. Which are the “well-known” ports?
  13. Which are the “ephemeral” ports?
  14. What is a socket?
  15. Which is the server advantage of using separate threads accepting connection requests?
  16. Which are the characteristics of a synchronous communication?
  17. Which are the characteristics of an asynchronous communication?
  18. Describe how packet switched network works.
  19. Describe how circuit switched network works.
  20. Compare packet switched and circuit switched network and give a description of the main differences.

CLIL Writing and Speaking - Java sockets

Answer to the following questions.

  1. Describe the Java classes used to create a TCP socket.
  2. Describe the Java classes used to create a UDP socket.
  3. Watch this video and answer to the following questions.
  1. In this video is not used a method that you used in all your TCP socket projects. Are you able to identify it?
  2. The class Socket uses different constructors, here you can find all of them. Try to identify which of them requires the use of the method you found on question one.

I sistemi distribuiti: modelli architetturali hardware e software


I sistemi distribuiti

Le architetture dei sistemi informativi si sono sviluppate ed evolute nel corso degli anni passando da schemi centralizzati a modelli distribuiti, più aderenti alla necessità di decentralizzazione e cooperazione delle moderne organizzazioni.

Si parla di sistema informatico centralizzato quando i dati e le applicazioni risiedono in un unico nodo elaborativo.

Un sistema informatico distribuito invece è costituito da un insieme di applicazioni logicamente indipendenti che collaborano per il perseguimento di obiettivi comuni attraverso una infrastruttura di comunicazione hardware e software.

Le applicazioni che costituiscono un sistema distribuito hanno ruoli diversi all’interno del sistema stesso, e sono identificate nel seguente modo:

  • Client: un’applicazione assume il ruolo di client quando è utilizzatore di servizi messi a disposizione da altre applicazioni;
  • Server: un’applicazione assume il ruolo di server quando è fornitore di servizi usati da altre applicazioni;
  • Actor: un’applicazione assume il ruolo di actor quando svolge sia il ruolo di client, sia quello di server in diverse situazioni nel contesto del sistema.

Alcuni esempi di sistemi distribuiti sono a livello macroscopico Internet, mentre a livello di singolo individuo può essere una PAN (Personal Area network) che fa riferimento al wearable computing,

o una rete di sensori.

Caratteristiche dei sistemi distribuiti

I sistemi distribuiti presentano una serie di caratteristiche che possono essere interpretate sia come vantaggi, sia come svantaggi, ma indubbiamente, vista l’attuale affermazione dell’uso dell'architettura distribuita per tutti i grandi sistemi informatici, è evidente che gli svantaggi sono considerati come un prezzo adeguato da pagare per garantirsi i vantaggi che derivano dall’uso di un sistema distribuito.

Affidabilità

Uno dei principali vantaggi dei sistemi distribuiti è l’affidabilità in quanto la ridondanza dei sistemi hardware e software, quando prevista ed implementata in modo sistematico, permette al sistema di sopravvivere al guasto di un suo componente, introducendo al limite un livello di inefficienza nei tempi di risposta.

Questa caratteristica è raggiungibile solo se vengono predisposti gli strumenti hardware e software in grado di intervenire automaticamente al verificarsi di situazioni indesiderate. Ad esempio, l’implementazione di algoritmi operativi che permettano alle entità non guaste di sostituire quella danneggiata per non interrompere il funzionamento del sistema sono un esempio di utilizzo di sistemi di backup che vengono attivati nel momento in cui l’elemento principale non sia più operativo.

Risulta però evidente che la difficoltà di realizzazione e i costi connessi di un simile sistema crescono con l’aumentare del livello di affidabilità che si vuole raggiungere, quindi non è sempre implementabile un sistema completamente affidabile.

Integrazione

Un’altra importante caratteristica dei sistemi distribuiti è la capacità di integrare componenti eterogenei tra loro, sia per tipologia hardware (dai PC ai mainframe, dagli smartphone ai tablet), sia per sistema operativo.

Per garantire questa caratteristica è fondamentale che ogni componente si possa interfacciare allo stesso modo con il sottosistema di comunicazione del sistema distribuito, indipendentemente dalle differenze hardware e di sistema operativo. L’interfaccia di comunicazione gioca quindi un ruolo fondamentale per permette di rendere trasparenti all’intera rete i componenti dello strato inferiore del sistema.

Un classico esempio di integrazione è la possibilità di connettere dispositivi di nuova generazione con sistemi legacy[1], che di fatto utilizzano tecnologie obsolete e spesso incompatibili con quelle più recenti.

Altri esempi di interfacce di comunicazione che soddisfano il criterio di integrazione è la tecnologia Ethernet per la connessione di dispositivi di rete, anche prodotti da società diverse, o la piattaforma Web che permette a sistemi operativi e architetture hardware di  interconnettersi e scambiarsi informazioni.

Un altro esempio di interfaccia volta al perseguimento dell’integrazione è costituita dalle API (Application Program Interface) che rappresentano un insieme di procedure, utilizzabili dal programmatore, utili alla stesura di applicazioni di rete. Le API forniscono l’interfaccia tra l’applicazione e lo strato di trasporto realizzando quella che si chiama astrazione tra hardware e programmazione, svincolando in tal modo gli sviluppatori dalle problematiche di comunicazione e trasferimento dati che sono i compiti degli strati inferiori. In particolare i socket API mettono a disposizione del programmatore gli strumenti necessari a sviluppare programmi di connessione che implementano il protocollo di comunicazione desiderato.

Il linguaggio XML (eXtensible Markup Language) è un’altra tecnologia che permette di integrare sistemi diversi in quanto è stato creato appositamente per favorire lo scambio di informazioni nel Web e permettere un’agevole ed efficiente pubblicazione di dati complessi.

In sostanza la caratteristica di integrazione è resa possibile dalla definizione di protocolli standard o sistemi architetturali de facto che favoriscono la portabilità di applicazioni fra sistemi operativi diversi, conservando la medesima interfaccia utente, e la interoperabilità tra componenti diversi.

Trasparenza

Con il termine trasparenza si intende il concetto di considerare il sistema distribuito non come un insieme di componenti ma come un sistema di elaborazione unico.

Lo scopo è quello di rendere trasparente all’utente la presenza di un sistema distribuito composto da molteplici entità, anche fisicamente distanti fra loro e con configurazioni mutevoli nel tempo, in modo che abbia invece la percezione di utilizzare un singolo elaboratore.

L’ANSA nell’ISO 10746, Reference Model of Open Distributed Processing, identifica otto forme di trasparenza, delle quali le prime due risultano fra le più importanti da implementare nell’ambito un sistema distribuito:

  • trasparenza di accesso (access transparency): permette l’accesso alle risorse locali e remote usando operazioni identiche e uniformi, nascondendo le differenze nella rappresentazione dei dati e nelle modalità di accesso;
  • trasparenza di locazione (location transparency): permette l’accesso alle risorse utilizzando un identificatore indipendente dalla reale disposizione geografica della risorsa stessa, ad esempio utilizzando un URL;
  • trasparenza di concorrenza (concurrency transparency): permette ai processi di operare in maniera concorrente per l’accesso ad una risorsa condivisa, lasciandola sempre in uno stato consistente implementando, per esempio, meccanismi di locking (semafori, monitor);
  • trasparenza di replicazione (replication transparency): permette di aumentare l’affidabilità e le prestazioni del sistema effettuando duplicazioni delle risorse mantenendone sempre lo stesso nome, e senza che l’utente ne abbia la percezione;
  • trasparenza ai guasti (failure transparency): permette di mascherato un eventuale guasto di una risorsa e l’eventuale ripristino;
  • trasparenza alla migrazione (mobility transparency): nasconde l’eventuale spostamento (logico o fisico) di una risorsa senza interferire sulla sua modalità di accesso, e quindi senza influenzare le operazioni degli utenti che la riguardano;
  • trasparenza alle prestazioni (performance transparency): nasconde le operazioni necessarie per riconfigurare il sistema al variare del carico, allo scopo di migliorarne le prestazioni;
  • trasparenza di scalabilità (scaling transparency): permette di espandere il sistema senza interromperne o modificarne il funzionamento.

Il perseguimento di ognuna di queste forme di trasparenza necessita di investimenti e competenze tecniche per realizzarle.

Economicità

Il rapporto costo-prestazione di un sistema distribuito permette effettivamente di considerare economico un investimento, anche ingente, per la sua realizzazione. Di fatti i costi, spesso notevoli, per realizzare un simile sistema vengono normalmente ripartiti fra una massa considerevole di utilizzatori, che beneficiano a tal punto dei servizi offerti dal sistema distribuito da essere disposti a sostenerne la spesa.

Rispetto ai costi di realizzazione di un sistema centralizzato di un tempo, basato su mainframe, il costo di un sistema distribuito risulta sicuramente maggiore di diversi ordini di grandezza, ma a differenza della vecchia tecnologia, il costo procapite dell’uso del sistema viene ripartito su un maggior numero di soggetti, fornendo anche un margine di guadagno di molto superiore.

Inoltre la possibilità di condividere risorse hardware e software comporta vantaggi economici dovuti alla condivisione di apparecchiature speciali di costo elevato, che diversamente potrebbero risultare sotto-utilizzate.

Infine un sistema distribuito ben progettato dovrebbe risultare facilmente scalabile permettendo l’aggiunta di componenti al fine di migliorarne le prestazioni realizzando un bilanciamento di carico.

Complessità

La complessità di un sistema distribuito ha richiesto lo sviluppo di hardware opportuno per garantire l’interconnessione dei suoi componenti e l’instradamento dei messaggi, in modo da fronteggiare adeguatamente la crescente richiesta dell’utenza.

Inoltre ha portato allo sviluppo di nuovi paradigmi di programmazione e di nuovi linguaggi, modificando radicalmente l’idea di programmazione e di sviluppo di sistemi software.

Infine sono sorte molteplici problematiche legate alla sicurezza che un tempo non era possibile neanche prevedere; l’accesso remoto alle risorse e lo sviluppo delle transazioni commerciali ha reso necessario lo sviluppo di sofisticate tecniche volte alla protezione dei dati e delle infrastrutture.


Storia dei sistemi distribuiti e modelli architetturali

L’obiettivo primario della progettazione dei computer è stato sempre quello di aumentarne le prestazioni, soprattutto in termini di velocità, in modo che si potessero eseguire il maggior numero di istruzioni nel minore tempo possibile.

Le velocità raggiungibili hanno però un limite superiore imposto dalle leggi della fisica sulla velocità della luce, che nel vuoto raggiunge i 300.000 Km/s, mentre nel rame è possibile approssimarla a 200.000 Km/s. Da ciò si deduce che per raggiungere frequenze di lavoro dell’ordine dei GigaHertz, e quindi tempi di esecuzione delle istruzioni dell’ordine dei ns, è necessario che le distanze percorse nei conduttori interni non superino i 20 cm (v = (200.000*103)/109 = 0,2 m/s). Le dimensioni dei componenti dei computer sono quindi importanti per non introdurre ritardi nell’esecuzione delle istruzioni.

L’eccessiva riduzione delle dimensioni degli elaboratori ha però provocato problematiche legate sia alla dissipazione dell’energia, sia alla meccanica quantistica che entra in gioco pesantemente provocando fenomeni non controllabili, ma che allo stesso tempo ha indirizzato lo sviluppo dei nuovi computer quantistici.

L’evoluzione dei computer non quantistici ha optato per una riorganizzazione dell’elaborazione che consentisse di costruire macchine sempre più performanti gestendo le informazioni in modo diverso, e quindi definendo architetture di elaborazione diverse, sia dal punto di vista costruttivo (hardware), sia dal punto di vista logico (software).

Dal punto di vista hardware si è passati alla realizzazione di macchine e sistemi dotati di più CPU in modo da avere più potenza di calcolo senza esasperare i limiti di velocità di ogni singola CPU, sviluppando di macchine parallele o macchine ad architettura parallela.

Per il software lo sviluppo delle architetture distribuite hanno permesso di seguire, se non addirittura anticipare, i cambiamenti delle architetture hardware e dei loro sistemi operativi.

CLIL Listening and Speaking - Quantum Computers

In these videos you will find how normal computer evolution has taken a strange path due to quantum mechanics. Watch the three videos and discuss the topic with your classmate.

  1. Transistors & The End of Moore's Law
  2. Quantum Computers Explained – Limits of Human Technology
  3. How Does a Quantum Computer Work?

Architetture distribuite hardware

Esistono diverse possibilità per classificare le architetture hardware a seconda dei fattori che si prendono come riferimento.

La tassonomia di Flynn[2] è un sistema di classificazione delle architetture dei calcolatori ideata da Michael J. Flynn fra gli anni ‘60 e ‘70 che permette di identificare i sistemi di calcolo a seconda della molteplicità del flusso di istruzioni e del flusso dei dati che possono gestire. In seguito questa classificazione è stata estesa con una sottoclassificazione per considerare anche il tipo di architettura della memoria.

A seconda di come si combinano il flusso di dati e il flusso delle istruzioni abbiamo quattro possibili macro-gruppi, che possono ulteriormente suddividersi considerando anche l’architettura della memoria.

SISD

L’architettura SISD (Single Instruction Single Data) è quella presente negli elaboratori che prevedono l’uso di una singola CPU, nei quali il flusso di istruzioni è unico e quindi viene eseguito un solo programma alla volta che agisce su un singolo flusso di dati. Dopo l’esecuzione di una istruzione si passa alla successiva seguendo un processo esecutivo rigorosamente sequenziale.

Un esempio teorico di questo tipo di architettura è costituito dalla macchina di Von Neumann, mentre nella realtà tutti i PC e i mainframe di vecchia generazione erano macchina ad una sola CPU e quindi la loro architettura era SISD.

SIMD

Le architetture SIMD (Single Instruction Multiple Data) sono composte da molte unità di elaborazione che eseguono contemporaneamente la stessa istruzione ma lavorano su insiemi di dati diversi. Generalmente, il modo di implementare le architetture SIMD è quello di avere un processore principale che invia le istruzioni da eseguire contemporaneamente ad un insieme di elementi di elaborazione che provvedono ad eseguirle. Il processore principale spesso è ospitato all'interno di un calcolatore convenzionale che provvede a supportare anche l'ambiente di sviluppo.

I sistemi SIMD sono utilizzati principalmente per supportare computazioni specializzate in parallelo, come ad esempio i supercomputer vettoriali usati per particolari applicazioni scientifiche dove si lavora su grandi matrici, gli array processor che in origine erano progettati per applicazioni di intelligenza artificiale e di calcolo simbolico, anche se versioni successive ebbero successo nelle scienze applicate che richiedevano elevate potenza di calcolo, e le GPU (Graphics Processing Unit) utilizzate per la grafica ad alto livello.

MISD

Le architetture MISD (Multiple Instruction Single Data) prevedono molteplici sistemi che eseguono processi diversi che agiscono su un unico flusso di dati. Questo tipo di architettura, pur non essendo particolarmente diffusa, viene usata generalmente in termini di tolleranza ai guasti (fault tolerance), in cui sistemi eterogenei devono operare sullo stesso flusso di dati dovendo concordare sul risultato finale. Un esempio reale è presente nel computer di controllo del volo dello Space Shuttle.

MIMD

L’architettura MIMD (Multiple Instruction Multiple Data) comprende tutte le tipologie di elaboratori composti da più unità centrali di elaborazione indipendenti che possono lavorare su stream di dati anch’essi indipendenti, raggiungendo un parallelismo a livello di thread.

Per questa architettura viene effettuata una ulteriore classificazione delle in base alla suddivisione della memoria fisica:

  • macchine MIMD a memoria fisica condivisa;
  • macchine MIMD a memoria fisica distribuita e privata.

Le prime sono anche conosciute con il nome di multiprocessor, mentre le seconde con quello di multicomputer.

MIMD a memoria fisica condivisa

I sistemi MIMD multiprocessori sono architetture a memoria fisica condivisa (shared memory) che costituisce un unico spazio di indirizzamento condiviso tra tutti i processori. Dato che la comunicazione tra processi avviene mediante variabili condivise, risulta necessario implementare opportuni meccanismi di sincronizzazione per regolare gli accessi alla memoria, in modo da coordinare i diversi processi per gestire la competizione alle risorse comuni.

In questo tipo di architettura non necessariamente i processori devono avere un’unica memoria in comune centralizzata, possono anche avere ciascuno una propria memoria e condividerne una parte con gli altri processori, in modo da realizzare una memoria condivisa distribuita.

MIMD a memoria fisica distribuita

I sistemi MIMD multicomputer sono architetture che non hanno una memoria condivisa e quindi la comunicazione avviene mediante lo scambio di messaggi (message passing) esplicito effettuato mediante apposite procedure (send e receive), come avviene utilizzando i socket. Ogni computer possiede una propria area di memoria privata, non indirizzabile da parte dei processori remoti.

Un tipico esempio di questa architettura è fornito dai cluster di PC.

Cluster di PC

Un computer cluster è un insieme di computer connessi tra loro tramite una rete, e nasce dall’esigenza di distribuire fra i vari computer del cluster elaborazioni molto complesse, scomponendole in sotto-elaborazioni separate che vengono eseguite in parallelo. Questo ovviamente aumenta la potenza di calcolo del sistema, solitamente garantendo un’alta disponibilità di servizio. Per contro la gestione dell’infrastruttura può avere maggiori costi e complessità di gestione, pur risultando economico nella sua implementazione, fortemente scalabile e affidabile.

Si può parlare propriamente di cluster di PC quando un insieme di computer completi e interconnessi ha le seguenti proprietà:

  • i vari computer appaiono all’utente come una singola risorsa computazionale;
  • le varie componenti sono risorse dedicate al funzionamento dell’insieme.

Teoricamente un cluster di PC ha una potenza di calcolo pari alla somma di quelle dei singoli computer che lo costituiscono, e differisce da una normale rete di PC principalmente:

  • per la velocità del trasferimento dati (oltre 1 Gbit/s);
  • per la centralizzazione fisica delle macchine (generalmente tutti i PC sono montati sullo stesso rack);
  • per la presenza di una applicazione di management, residente su un singolo PC, che permette di lanciare processi su altri PC, monitorare il loro comportamento.

In base alla definizione e considerando le unità centrali come entità, un sistema cluster di PC corrisponde all’insieme delle macchine MIMD a memoria privata. L’enorme vantaggio dei cluster di PC è quello di affrontare calcoli particolarmente onerosi che sarebbero molto lunghi o impossibili con un solo computer e di ridurre il gravoso inconveniente del tempo di elaborazione anche per quei problemi che si potrebbero risolvere con un singolo computer ma al prezzo di un tempo molto elevato.

CLIL Listening and Speaking - Flynn Taxonomy and Cluster Architecture

In these videos you will understand the Flynn’s taxonomy and why cluster architecture is widely used in big enterprise. Watch the videos and discuss the topics with your classmate.

  1. Flynn's Taxonomy of Parallel Machines - Georgia Tech - HPCA: Part 5
  2. Big Ideas: Simplifying Cluster Architectures

Architetture distribuite software

Come per l’hardware, anche per il software si è avuta avuto una evoluzione nelle architetture distribuite che spesso hanno anticipato i cambiamenti delle architetture hardware e dei loro sistemi operativi, passando attraverso tre fasi principali: l’architettura centralizzata, l’architettura client-server e l’architettura multi-tier.

Architettura centralizzata

La prima architettura di elaboratori, definita anche 1 tier o ad un livello (anni ‘70), prevedeva un’unica unità centrale di elaborazione (mainframe) a cui erano collegati terminali privi di capacità computazionali. Lo scopo dei terminali remoti era quello di inviare i dati all’unità centrale e di ricevere i relativi risultati per visualizzarli, mentre l’unità centrale gestiva i dati, la logica di business e l’interfaccia utente.

I terminali remoti avevano solitamente caratteristiche omogenee e l’unità centrale replicava per ciascuno di essi un’area di memoria riservata, facendo evolvere singolarmente i singoli task avviati dai diversi terminali remoti.

I principali vantaggi di questa architettura erano l’elevata sicurezza delle funzioni, l’efficienza esecutiva, in quanto non era previsto un overhead per la comunicazione remota in fase elaborativa e uno sviluppo architetturale relativamente semplice. Per contro l’hardware era estremamente costoso, poco scalabile e il sistema presentava molti problemi di integrazione in quantoƒ erano solitamente sistemi chiusi.

Alla base dell’evoluzione di questa architettura c’è principalmente la nascita della rete Internet, che pur non essendo inizialmente quella che oggi conosciamo, presenta possibilità che spingono fortemente verso una maggiore distribuzione. Contemporaneamente inizia una spinta di informatizzazione presso le piccole e medie imprese vista la massiva produzione di client più prestanti e a costi contenuti se paragonati ai mainframe usati nelle grandi aziende.

Architettura client-server

L’architettura client-server, definita anche architettura a due livelli o 2 tier (anni ‘80), a differenza della precedente prevede dei client con una loro capacità di elaborazione in grado di iniziare la richiesta di un servizio ad un server, che invece si occupa di elaborare la richiesta e inviare la risposta al client.

Un client può richiedere più servizi a server diversi e un server può ricevere più richieste da molteplici client. Inoltre un server può assumere il ruolo anche di client nel momento in cui necessita di un servizio offerto da un altro server per soddisfare la richiesta iniziale del client.

In questo tipo di architetture due client possono collaborare tra loro unicamente attraverso uno o più server che permettono la coordinazione e la condivisione dei dati. Client e server possono essere tecnologicamente diversi, sia come hardware che come sistema operativo, e in generale questa architettura è quella che meglio si presta a far comunicare e cooperare entità non omogenee.

La comunicazione tra client e server avviene mediante protocolli ben definiti e generalmente sono sistemi aperti che riescono a raggiungere un buon livello di integrazione. Generalmente l’hardware può o meno essere costoso a seconda della potenza di calcolo richiesta, richiede un discreto costo di amministrazione, soprattutto per questioni di sicurezza e la scalabilità dipende dalla progettazione effettuata a monte.

Nel tempo questa architettura ha previsto lo sviluppo di due modelli:

  • il modello thin-client (primi anni ‘80) in cui il server è il responsabile della logica applicativa e della gestione dei dati, mentre il client è responsabile dell’esecuzione del software di presentazione;
  • il modello thick-client o fat-client (fine anni ‘80) in cui il server è responsabile della gestione dei dati, mentre il client è responsabile del software di presentazione e della logica applicativa, grazie all’aumento della potenza di calcolo dei PC.

Le principali ragioni che hanno portato un’evoluzione rispetto a questa architettura sono ascrivibili alla standardizzazione dei protocolli di rete, al crescente ampliamento della banda disponibile, alla necessità di distribuire l’informazione e i servizi su media diversi e di gestire molte transazioni on line, oltre alla necessità di evitare, per questioni di sicurezza, il single point of failure.

Architettura multi-tier

Per alleggerire il carico elaborativo dei server vennero sviluppati sistemi multilivello (anni ‘90), nei quali avvenne la separazione delle funzionalità logiche del sistema in livelli software diversi. Allo scopo vennero introdotti un insieme di strumenti, complessivamente identificati con il termine middleware, che rappresenta uno strato software che si colloca sopra al sistema operativo ma sotto i programmi applicativi, rappresentando l’evoluzione dei sistemi operativi distribuiti.

Il modello a multi-tier richiede una chiara definizione delle interfacce e dei protocolli di comunicazione usati fra i vari livelli, in modo che possano richiedere ed offrire servizi fra loro. Inoltre questa separazione logica delle funzionalità permette di apportare modifiche ai vari livelli, limitando al minimo l’impatto sugli altri livelli.

In genere l’architettura multi-tier prevede lo sviluppo di applicazioni su tre livelli distinti:

  1. Presentation Layer: rappresenta l’interfaccia utente ed è composta dall’insieme delle procedure dedicate all’acquisizione e alla presentazione dei dati all’utente (maschere di input, organizzazione di tabelle e tabulati video/cartacei). Per esempio, nei sistemi Web che visualizzano pagine HTML, il Presentation Layer è costituito dai moduli del Web Server che concorrono a creare i documenti HTML, come le Java Servlet, gli script PHP e ASP, mentre il client può essere identificato con il browser.
  2. Business Logic Layer o Application Logic Layer: è il corpo centrale dell’applicazione che comprende la logica di elaborazione e la definizione  delle relazioni esistenti tra le diverse entità. Per esempio, questo layer potrebbe comprende l’algoritmo che implementa le operazioni legate a un prelievo su un conto corrente bancario, o la sequenza di passi da compiere per effettuare un acquisto on-line.
  3. Resource Management Layer: è composto dall’insieme delle procedure che gestiscono i dati, cioè memorizzano e recuperano le informazioni persistenti dagli archivi di massa delle basi di dati. Nel caso in cui esso sia implementato tramite un DBMS, questo layer è detto semplicemente Data Access Layer.

I principali vantaggi di questa architettura sono la scalabilità, la possibilità di applicare sistemi di sicurezza a livello di singolo servizio e con livelli diversi a seconda del layer considerato.

Sicuramente un’architettura di questo tipo è complicata sia a livello progettuale, sia a livello di sviluppo e amministrazione.

In ogni caso questo modello permette lo sviluppo di architetture distribuite che prevedono la specializzazione dei server per servizi diversi, bilanciare il carico di lavoro tra varie entità e l’integrazione di servizi che risiedono su server diversi.

CLIL Listening and Speaking - n-Tier Architecture

In these videos you will understand how n-tier architecture works. Watch the videos and discuss the topics with your classmate.

  1. 3 Tier Client Server Architecture
  2. n-Tier Architecture Explained
  3. N-Tier Architecture for kids
  4. Middleware Architecture

Middleware

Il middleware ha lo scopo di realizzare la comunicazione e le interazioni tra i diversi componenti software di un sistema distribuito e rappresenta una classe di tecnologie software sviluppate per aiutare gli sviluppatori nella gestione della complessità e della eterogeneità presenti nei sistemi distribuiti.

Il middleware è quindi un software di connessione che consiste di un insieme di servizi e/o ambienti di sviluppo di applicazioni distribuite che permettono a più entità (processi, oggetti, ecc.), residenti su uno o più elaboratori, di interagire attraverso una rete di interconnessione a dispetto di differenze nei protocolli di comunicazione, architetture dei sistemi locali e sistemi operativi.

Di conseguenza il middleware garantisce:

  • interoperabilità o integrazione tra applicazioni e sistemi operativi diversi;
  • connettività tra servizi che devono interagire e collaborare su piattaforme distribuite, utilizzando meccanismi di programmazione e API.

Di fatto la presenza di questo strato rende facilmente programmabili i sistemi distribuiti offrendo una specifica modalità di interazione, che può essere per esempio un paradigma di interazione basato sulla chiamata di procedure remote (RPC Remote Procedure Call) oppure un paradigma di programmazione basata sullo scambio di messaggi (Socket).

Tra le funzionalità del middleware ricordiamo:

  • servizi di astrazione e cooperazione: rappresentano il cuore del middleware e comprendono:
  • directory service: provvede alla identificazione e alla localizzazione delle entità, rendendo le applicazioni al di sopra del middleware indipendenti dal sottosistema di instradamento dei messaggi (trasparenza di locazione);
  • security service: finalizzato alla protezione degli elementi critici, come i dati e i servizi applicativi, utilizzando tecniche di autenticazione, autorizzazione e crittografia;
  • time  service: assicura che tutti i clock interni tra client e server siano sincronizzati entro un accettabile livello di varianza.
  • servizi per le applicazioni: permettono alle applicazioni di avere un accesso diretto con la rete e con i servizi offerti dal middleware, ad esempio, un servizio orientato alle transazioni può fornire un supporto per un accesso transazionale a basi di dati eterogenee;
  • servizi di amministrazione del sistema: servono per effettuare monitoraggio, configurazione e pianificazione di interventi sul sistema;
  • servizio di comunicazione: questo servizio offre delle API che permettono all’applicazione distribuita di scambiare informazioni fra tutte le sue componenti residenti su altri elaboratori aventi anche caratteristiche hardware o software diverse. Lo scopo di questo servizio è di nascondere le disomogeneità dovute alla rappresentazione dei dati usata dai vari elaboratori, dai sistemi operativi locali e dalle diverse reti che costituiscono l’infrastruttura della piattaforma. I paradigmi di comunicazione possono essere basati su RPC, messaggistica applicativa, o altre;
  • ambiente di sviluppo applicativo: offre diversi tool, come strumenti di aiuto alla scrittura di programmi, debugging. gestione di applicativi sia ad oggetti che a processi, Interface Definition Language che permette l'interconnessione tra moduli scritti in diversi linguaggi di programmazione e residenti su elaboratori distinti.

Il middleware offre molti servizi, anche più di quanti in realtà potrebbero essere necessari per una applicazione, e quindi a livello progettuale si dovrà mediare prestazioni dell’applicazione e efficienza esecutiva, cercando di includere solo i servizi necessari per non appesantire troppo il sistema finale.

CLIL Listening and Speaking - Middleware

In this video you will understand what middleware is. Watch the videos and discuss the topics with your classmate.

  1. Middleware Concepts

Export Pages SOII-middleware_2.png

Export Pages SOII-middleware_3.png

Export Pages SOII-middleware_4.png

Export Pages SOII-middleware_5.png

Export Pages SOII-middleware_6.png

Export Pages SOII-middleware_7.png

Export Pages SOII-middleware_8.png

Java e XML


A6 Gestione dei documenti in formato XML

STUDIARE: G. Meini, F. Formichi, Tecnologie di progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2017, pp.141-146.

LEGGERE: G. Meini, F. Formichi, Tecnologie di progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2017, pp.146-163.

Esempi di parsing di un documento XML con DOM

Esempio 1

Consideriamo il seguente documento XML che utilizzeremo per fare un esempio di parsing.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<libri>
   
<libro genere="fantascienza">
                  
<autore>Stefano Benni</autore>
                  
<titolo>Terra!</titolo>
                  
<prezzo>10.50</prezzo>
   
</libro>
   
<libro genere="romanzo">
                   
<autore>Mark Twain</autore>
                    
<titolo>Le avventure di Huckleberry Finn</titolo>
                    
<prezzo>9.90</prezzo>
   
</libro>
   
<libro genere="romanzo">
                    
<autore>Herman Melville</autore>
                    
<titolo>Moby Dick</titolo>
                    
<prezzo>15.00</prezzo>
   
</libro>
</libri>


Il DOM del documento XML sarà il seguente.

Di seguito viene fornito un esempio di un semplice parser del file XML mostrato in precedenza, presupponendo di conoscere i nomi dei nodi attraversati.

import java.io.IOException;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

public class Parser {
   
 
public void parseDocument(String filename)
     
throws ParserConfigurationException, SAXException, IOException {
   
/**
            * DocumentBuilderFactory è una API di tipo factory necessaria per
            * ottenere un parser per la produzione di un oggetto albero DOM da un
            * documento XML.
            * Istanziamo un DocumentBuilderFactory per la generazione di un albero
            * DOM da un documento XML.
            */

    DocumentBuilderFactory factory  = DocumentBuilderFactory.newInstance();
   
/**
            * DocumentBuilder è una API per ottenere una interfaccia di tipo
            * "Document" DOM da un documento XML.
            * Istanziamo un DocumentBuilder per generare un oggetto di tipo
            * "Document".
            */

    DocumentBuilder builder = factory.newDocumentBuilder();
   
/**
            * L'interfaccia "Document" rappresenta un intero documento XML (o HTML).
            * Concettualmente è la radice dell'albero del documento e fornisce
            * l'accesso principale ai dati del documento.
            * Il metodo parse(File f) parsifica il contenuto del file XML e
            * restituisce un nuovo oggetto "Document" DOM, cioé costruiamo l'albero
            * DOM del file XML.
            */

    Document document = builder.parse(filename);
   
/**
            * L'interfaccia Element rappresenta un elemento di un documento XML
            * (o HTML).
            * Estraiamo l'elemento radice del documento.
            */

    Element root = document.getDocumentElement();
   
// L'oggetto di tipo NodeList conterrà l'insieme degli elementi estratti
   
// dall'albero DOM a partire dalla posizione indicata.
    NodeList nodelist;
   
// L'oggetto di tipo Element servirà per estrarre i singoli elementi
   
// recuperati tramite un oggetto NodeList.
    Element element;
           
   
// Estrazione di tutti gli elementi figli il cui nome è "libro".
    nodelist = root.getElementsByTagName(
"libro");
   
if (nodelist != null && nodelist.getLength() > 0) {
       
for (int i = 0; i < nodelist.getLength(); i++) {
           
// Scorriamo ogni singolo elemento "libro".
            element = (Element)nodelist.item(i);
           
// Recupero del valore dell'attributo specificato.
            System.out.println(
"Genere: " + element.getAttribute("genere"));
           
// Per recuperare i valori degli elementi figli bisogna
           
// istanziare un nuovo oggetto NodeList. Utilizzeremo un metodo
           
// creato proprio per questo scopo, getTextValue().
            String titolo = getTextValue(element,
"titolo");
            String autore = getTextValue(element,
"autore");
           
float prezzo = Float.parseFloat(getTextValue(element,"prezzo"));
            System.out.println(
"Titolo: " + titolo);
            System.out.println(
"Autore: " + autore);
            System.out.println(
"Prezzo: " + prezzo);
        }
           }
 }
   
 
private String getTextValue(Element element, String tag) {
    String value =
null;
    NodeList nl;
           
    nl = element.getElementsByTagName(tag);
   
if (nl != null && nl.getLength() > 0) {
       
// Recupero del valore del nodo - getNodeValue() - del primo figlio
       
// - getFirstChild() - dell'elemento nella posizione 0 della
       
// collezione dell'oggetto NodeList - item(0) -.
        value = nl.item(
0).getFirstChild().getNodeValue();
    }
           
   
return value;
 }

 
public static void main(String[] args)
               
throws ParserConfigurationException, SAXException, IOException {
           Parser parser =
new Parser();
           
           parser.parseDocument(
"libri.xml");
        
/**
         * Avendo il documento xml in una stringa (nell’esempio di nome s) è
         * possibile utilizzare uno stream di byte direttamente in memoria:
       *
ByteArrayInputStream stream=new ByteArrayInputStream(s.getBytes());
       *
parser.parseDocument(stream);
         */

 }
}


L’esecuzione del parser fornirà il seguente output.

Genere: fantascienza
Titolo: Terra!
Autore: Stefano Benni
Prezzo: 10.5
Genere: romanzo
Titolo: Le avventure di Huckleberry Finn
Autore: Mark Twain
Prezzo: 9.9
Genere: romanzo
Titolo: Moby Dick
Autore: Herman Melville
Prezzo: 15.0


Esempio 2

Di seguito viene fornito un esempio alternativo in cui i nodi del DOM vengono visualizzati tramite un ciclo, presupponendo di non conoscerne il nome.

import java.io.IOException;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;

public class Parser {
   
 
public void parseDocument(String filename)
     
throws ParserConfigurationException, SAXException, IOException {
   
/**
            * DocumentBuilderFactory è una API di tipo factory necessaria per
            * ottenere un parser per la produzione di un oggetto albero DOM da un
            * documento XML.
            * Istanziamo un DocumentBuilderFactory per la generazione di un albero
            * DOM da un documento XML.
            */

    DocumentBuilderFactory factory  = DocumentBuilderFactory.newInstance();
   
/**
            * DocumentBuilder è una API per ottenere una interfaccia di tipo
            * "Document" DOM da un documento XML.
            * Istanziamo un DocumentBuilder per generare un oggetto di tipo
            * "Document".
            */

    DocumentBuilder builder = factory.newDocumentBuilder();
   
/**
            * L'interfaccia "Document" rappresenta un intero documento XML (o HTML).
            * Concettualmente è la radice dell'albero del documento e fornisce
            * l'accesso principale ai dati del documento.
            * Il metodo parse(File f) parsifica il contenuto del file XML e
            * restituisce un nuovo oggetto "Document" DOM, cioé costruiamo l'albero
            * DOM del file XML.
            */

    Document document = builder.parse(filename);
   
/**
            * L'interfaccia Element rappresenta un elemento di un documento XML
            * (o HTML).
            * Estraiamo l'elemento radice del documento.
            */

    Element root = document.getDocumentElement();
   
// L'oggetto di tipo NodeList conterrà l'insieme degli elementi estratti
   
// dall'albero DOM a partire dalla posizione indicata.
    NodeList nodelist;
   
// L'oggetto di tipo Element servirà per estrarre i singoli elementi
   
// recuperati tramite un oggetto NodeList.
    Element element;
           
   

     // Estrazione di tutti gli elementi figli il cui nome è "libro".
    nodelist = root.getElementsByTagName(
"libro");
   
if (nodelist != null && nodelist.getLength() > 0) {
       
for (int i = 0; i < nodelist.getLength(); i++) {
           
// Scorriamo ogni singolo elemento "libro".
            element = (Element)nodelist.item(i);
           
// Recupero del valore dell'attributo specificato.
            System.out.println(
"Genere: " + element.getAttribute("genere"));
           
// Per recuperare i valori degli elementi figli bisogna
           
// istanziare un nuovo oggetto NodeList.
            NodeList nl;
           
// Si recuperano i nodi figli del nuovo NodeList.
            nl = element.getChildNodes();

           
if (nl != null && nl.getLength() > 0) {
               
for (int j = 0; j < nl.getLength(); j++) {
                   
// Si scorrono i singoli elementi del NodeList.
                    Node n = nl.item(j);
                   
// Si controlla che il nodo estratto sia proprio un
                   
// elemento. Allo scopo viene utilizzata la costante
                   
// ELEMENT_NODE.
                   
if (n.getNodeType() == Node.ELEMENT_NODE) {
                       
// Recupero del nome dell'elemento.
                        String nodeName = n.getNodeName();
                       
// Recupero del valore testuale memorizzato nel
                       
// nodo.
                        String value = n.getTextContent();

                        System.out.println(nodeName +
": " + value);
                    }
                }
             }
         }
           }
 }

 
public static void main(String[] args)
               
throws ParserConfigurationException, SAXException, IOException {
           Parser parser =
new Parser();
           
           parser.parseDocument(
"libri.xml");
     
/**
         * Avendo il documento xml in una stringa (nell’esempio di nome s) è
         * possibile utilizzare uno stream di byte direttamente in memoria:
       *
ByteArrayInputStream stream=new ByteArrayInputStream(s.getBytes());
       *
parser.parseDocument(stream);
         */

 }
}


L’esecuzione del parser fornirà il seguente output.

Genere: fantascienza
autore: Stefano Benni
titolo: Terra!
prezzo: 10.50
Genere: romanzo
autore: Mark Twain
titolo: Le avventure di Huckleberry Finn
prezzo: 9.90
Genere: romanzo
autore: Herman Melville
titolo: Moby Dick
prezzo: 15.00


Esempio 3

Di seguito viene fornito un esempio alternativo in cui i nodi del DOM vengono visualizzati tramite un ciclo, presupponendo di non conoscerne il nome. La visualizzazione riflette la struttura del documento XML. Il codice è più complesso dei precedenti in quanto utilizza, fra le altre cose, il concetto di ricorsione.

import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class Parser {
 
public static void main(String[] args) throws SAXException, IOException,
ParserConfigurationException {
   
/**
            * DocumentBuilderFactory è una API di tipo factory necessaria per
            * ottenere un parser per la produzione di un oggetto albero DOM da un
            * documento XML.
            * Istanziamo un DocumentBuilderFactory per la generazione di un albero
            * DOM da un documento XML.
            */

           DocumentBuilderFactory documentBuilderFactory =
                   DocumentBuilderFactory.newInstance();
 
/**
    * Il metodo setNameSpaceAware() specifica che il parser prodotto
    * da questo codice supporterà i namespace XML.
    */

           documentBuilderFactory.setNamespaceAware(
true);
   
/**
            * DocumentBuilder è una API per ottenere una interfaccia di tipo
            * "Document" DOM da un documento XML.
            * Istanziamo un DocumentBuilder per generare un oggetto di tipo
            * "Document".
            */

           DocumentBuilder documentBuilder =
                   documentBuilderFactory.newDocumentBuilder();
   
/**
            * L'interfaccia "Document" rappresenta un intero documento XML (o HTML).
            * Concettualmente è la radice dell'albero del documento e fornisce
            * l'accesso principale ai dati del documento.
            * Il metodo parse(File f) parsifica il contenuto del file XML e
            * restituisce un nuovo oggetto "Document" DOM, cioé costruiamo l'albero
            * DOM del file XML.
            */

           Document doc = documentBuilder.parse(
"books.xml");
   
/**
            * L’interfaccia Node è il tipo fondamentale di un DOM e rappresenta un
      * singolo nodo nell’albero del documento.
      * Il metodo getDocumentElement() permette di accedere direttamente al
      * nodo figlio del documento, che in questo caso è la radice del      
      * documento.
            */

     Node root = doc.getDocumentElement();

     
// Il metodo printNodes() elabora solo gli elementi del documento DOM,
     
// evitando gli spazi e le tabulazioni inserite per chiarezza di
     
// lettura.
     
// Il valore restituito da printNodes() non viene prelevato in quanto
     
// ora non serve, essendo la prima chiamata del metodo ricorsivo.
     printNodes(root,
0);

 }
 
 
/**
   * Il metodo printNodes() elabora solo gli elementi del documento DOM,
   * evitando gli spazi e le tabulazioni inserite per chiarezza di lettura.
   * E’ un metodo ricorsivo, cioè richiama se stesso.
   */

 
private static int printNodes(Node node, int level) throws DOMException {
     
// Il nodo viene elaborato solo se è un elemento, cioè se non è un
     
// nodo formato da soli return o tabulazioni inseriti nell’XML per
     
// chiarezza di lettura.
           
if (node.getNodeType() == Node.ELEMENT_NODE) {
         String name = node.getNodeName();
         
// Si stampano degli spazi per ottenere la stampa indentata
         
// secondo il livello del nodo. Il metodo printSpaces() stampa
         
// tanti spazi quanto indicato nel parametro attuale, moltiplicati
         
// per 7.
         printSpaces(level);
         System.out.print(name +
" : ");
         String value =
null;
         
// Prelevo il valore del nodo che viene rappresentato come
         
// un nodo figlio.
         
if (node.getChildNodes() != null 
               && node.getChildNodes().getLength() >
0) {
             value = node.getFirstChild().getNodeValue();
         }
         
// La stampa viene effettuata solo se il valore contiene
         
// informazioni significative.
         
if (value != null) {
             value = value.trim();
         }
else {
             value =
"";
         }
         System.out.println(value);
         
// Un oggetto che implementa l’interfaccia NameNodeMap viene usato
         
// per rappresentare una collezione di nodi a cui si accede
         
// tramite nome. In questo caso viene usato per collezionare tutti
         
// gli attributi del nodo di riferimento.
         NamedNodeMap attributes = node.getAttributes();
         
if (attributes != null && attributes.getLength() > 0) {
             
for (int i = 0; i < attributes.getLength(); i++) {
                    
// Si accede alla collezione di attributi tramite indice.
                 Node n = attributes.item(i);
                 printSpaces(level);
                 System.out.println(
"A - " + n.getNodeName() + " : " +
                      n.getNodeValue().trim());
             }
         }
         
// Per ogni nodo figlio viene invocato ricorsivamente il metodo
         
// aumentando di 1 il livello di indentazione.
         NodeList list = node.getChildNodes();
         
if (list != null && list.getLength() > 0) {
             
for (int i = 0; i < list.getLength(); i++) {
                 level = printNodes(list.item(i), level +
1);
             }
         }
     }
     
// Avendo richiamato ricorsivamente il metodo, ogni richiamo che termina
     
// decrementerà di uno il livello di indentazione della stampa, proprio
     
// perché “si torna indietro”.
     
return level - 1;
 }

 
// Il metodo printSpaces() stampa tanti spazi quanto sono quelli indicati
 
// nel parametro formale moltiplicato per 7.
 
private static void printSpaces(int level) {
     
for (int i = 0; i < level; i++) {
          System.out.print(
"\t");
           }
 }
}


L’esecuzione del parser fornirà il seguente output.

libri :
          libro :
          A - genere : fantascienza
                 autore : Stefano Benni
                 titolo : Terra!
                 prezzo : 10.50
          libro :
          A - genere : romanzo
                 autore : Mark Twain
                 titolo : Le avventure di Huckleberry Finn
                 prezzo : 9.90
          libro :
          A - genere : romanzo
                 autore : Herman Melville
                 titolo : Moby Dick
                 prezzo : 15.00


HTTP e Servlet


A8 Realizzazione di web-service di tipo REST in linguaggio Java

STUDIARE: G. Meini, F. Formichi, Tecnologie di progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2017 pp.225-231.

CLIL Reading - What is a servlet and HTTP

JavaTpoint - Servlet tutorial

GET request

Nel metodo GET la coppia nome/valore, detta query string, è inviata all’interno dell’URL della richiesta GET. In una richiesta GET non esistendo il body, i dati necessari per la richiesta vengono trasportati direttamente come parametri nell’URL.

http://localhost:8084/Dati/Utente?nome=Maria+Grazia&cognome=Maffucci

Un header possibile della richiesta GET è il seguente:

Host: localhost:8084
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:8084/Dati/
Connection: keep-alive
Upgrade-Insecure-Requests: 1

Un possibile header della risposta del server è il seguente:

Content-Length: 251
Content-Type: text/html;charset=UTF-8
Date: Sat, 07 Jan 2017 21:28:50 GMT
Server: Apache-Coyote/1.1

Mentre il body della risposta del server potrebbe essere la pagina HTML seguente:

<!DOCTYPE html>
<html>
 
<head>
     
<title>Dati</title>
     
<style>
       
p.spesso {
         font-weight: bold;
       }
     
</style>
 
</head>
 
<body>
     
<p>Ciao Maria Grazia Maffucci</p>
     
<p class="spesso">Sat Jan 07 22:28:50 CET 2017</p>
 
</body>
</html>


POST request

Nel metodo POST la coppia nome/valore, detta query string, è inviata all’interno del body del messaggio HTTP della richiesta POST.

http://localhost:8084/Dati/Utente
Content-Type: application/x-www-form-urlencoded
Content-Length: 34

nome=Maria+Grazia&cognome=Maffucci

Un header possibile della richiesta POST è il seguente:

Host: localhost:8084
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.0
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://localhost:8084/Dati/
Connection: keep-alive
Upgrade-Insecure-Requests: 1

Un possibile header della risposta del server è il seguente:

Content-Length: 251
Content-Type: text/html;charset=UTF-8
Date: Sat, 07 Jan 2017 21:54:49 GMT
Server: Apache-Coyote/1.1

Mentre il body della risposta del server potrebbe essere la pagina HTML seguente:

<!DOCTYPE html>
<html>
 
<head>
     
<title>Dati</title>
     
<style>
       
p.spesso {
         font-weight: bold;
       }
     
</style>
 
</head>
 
<body>
     
<p>Ciao Maria Grazia Maffucci</p>
     
<p class="spesso">Sat Jan 07 22:28:50 CET 2017</p>
 
</body>
</html>

HTTP status code

Le coppie di valori status-code di HTTP sono delle risposte standard restituiti dai Web server. Questi codici aiutano ad identificare la causa di un problema nel caso non si riuscisse a trovare la pagina Web o la risorsa richiesta.

Gli status-code HTTP includono sia un codice numerico, sia una frase esplicativa. Ad esempio, la linea di stato HTTP 500: Internal Server Error segnala l’impossibilità del server di soddisfare la richiesta.

Un elenco degli HTTP status code è possibile trovarlo a questo link.

CLIL Reading - Servlet

JavaTpoint - Servlet tutorial

  • Web Terminology

Esercizi sulle Servlet

  1. Progettare una servlet in grado di visualizzare una frase di benvenuto. La servlet dovrà essere richiamata tramite un link in una pagina HTML.

  1. Progettare una servlet che visualizzi il tuo nome e cognome preventivamente inseriti in un form iniziale, congiuntamente alla date e ora del sistema in cui viene eseguita. Il nome e il cognome dovranno essere passati come parametri alla servlet.
    Per svolgere questo esercizio potete trarre spunto dal laboratorio 2 della UdA 3 del libro, pp.234-239.
    Il risultato finale dovrà essere simile a quanto mostrato di seguito.


  2. Modificare l’esercizio precedente prevedendo l’inserimento nel file web.xml di due parametri costanti di inizializzazione. Un parametro deve permettere di impostare il titolo della pagina generata dinamicamente dalla  servlet (ad es. Pagina di benvenuto), mentre l’altro deve essere utilizzato per scrivere un saluto subito dopo l’elenco dei dati (ad es. Ciao) riportando il nome e il cognome inseriti nel form iniziale.
    Provare a gestire i parametri di configurazione nei due seguenti modi, creando due progetti distinti:
  1. usando il metodo init() e il metodo getInitParameter() come mostrato sul libro di testo a p.187;
  2. lavorando direttamente nel metodo che implementa la servlet utilizzando la classe ServletConfig, il metodo getServletConfig() e infine il metodo getInitParameter(), come mostrato in questo link.

Il risultato finale, in entrambi i casi, dovrà essere simile al seguente.

  1. Progettare una servlet che, dopo che l’utente ha inserito due valori numerici interi tramite un form, generi la tabellina relativa.

  1. Progettare una servlet che permetta di fare un sondaggio culinario, raccogliendo in un file binario le preferenze di alcuni piatti.
    La servlet deve permettere la scelta fra più piatti tramite dei radio button e, una volta inviato il form, dovranno essere visualizzate le attuali percentuali di gradimento. Prendere spunto dall’esercizio proposto sul libro di testo a p.238.

  2. Progettare un’applicazione Web che permetta di effettuare un login (elementare) ad un sito. Se la password inserita risulta corretta l’utente deve essere reindirizzato ad una pagina di benvenuto che visualizzi il nome dell’utente (scegliete voi la password). Se invece la password risultasse scorretta, si dovrà segnalare l’errore riproponendo il form per l’inserimento del nome utente e della password. Utilizzare la classe RequestDispatcher per il passaggio dei parametri. Un esercizio analogo lo trovate a questo link.


  3. Progettare un’applicazione Web in grado di chiedere l’inserimento di due valori, il primo sarà il nome di un nuovo cookie, mentre il secondo sarà il valore assunto dal cookie. Una volta inseriti i due valori la pagina Web dovrà visualizzare l’elenco di tutti i cookie inseriti sino a quel momento, fornendo la possibilità di inserirne altri.
  4. Progettare un’applicazione Web che preveda inizialmente la scelta di un colore da un listbox. Il server risponderà inviando una pagina con lo sfondo del colore selezionato. Da quest’ultima pagina si dovrà richiedere l’invio di una seconda pagina al server, tramite un link, anch’essa con il colore dello sfondo scelto inizialmente. Usare i cookie per memorizzare il colore scelto.


  5. Progettare una servlet in grado di visualizzare il numero di volte che è stata eseguita, evidenziando quando viene eseguita la prima volta. Utilizzare le sessioni per gestire il conteggio.
  6. Modificare la servlet precedente visualizzando la data di creazione della servlet e modificando il tempo di terminazione della sessione riducendolo a 3 minuti (o valore inferiore) in modo tale che, provando ad eseguirla dopo il tempo di chiusura della sessione, il contatore ricomincerà nuovamente il conteggio.
  7. Progettare una applicazione Web in cui l’utente può inserire il proprio nome e scegliere un linguaggio di programmazione oggetto di studio. Inviando il form il server dovrà visualizzare una nuova pagina in cui verrà visualizzato un saluto all’utente ed un commento sul linguaggio di programmazione. Questa seconda pagina dovrà richiedere una terza pagina al server in cui verranno visualizzati:
  1. l’identificatore della sessione;
  2. la data di creazione della sessione;
  3. la data dell’ultimo accesso alla sessione;
  4. il nome dell’utente;
  5. il linguaggio di programmazione selezionato.

Si effettui opportunamente il passaggio dei parametri fra le due servlet utilizzando i parametri di sessione.



Web Service REST


A7 Web-service di tipo REST: interazione con linguaggio Java

STUDIARE: G. Meini, F. Formichi, Tecnologie di progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2017 pp.198-224.

Ragioni dell’uso dei Web service

Integrazione

I Web service permettono di usare il vecchio software e di implementare le sole funzionalità necessarie per gestire una infrastruttura. Ad esempio, è possibile sviluppare un nuovo programma finanziario in Java per una compagnia che già disponeva di un vecchio software per la gestione dei salari degli impiegati, sviluppato tramite una vecchia piattaforma .net. Questo vecchio programma sarà integrato con il nuovo software che userà delle funzionalità apposite per interfacciarsi con il sistema legacy. Questo è possibile proprio perché i dati scambiati fra le applicazioni sono nettamente isolati. I Web service sono il collante che permettono una semplice comunicazione fra applicazioni o anche fra organizzazioni diverse.

Usabilità

I Web service permettono di esporre sul Web il Business logic layer di molti sistemi usando API specifiche, fornendo alle applicazioni client remote la possibilità di scegliere il Web service di cui necessitano. In questo modo, sul lato client potranno essere aggiunti i servizi che si vogliono, sviluppati utilizzando i linguaggi e i tool preferiti.

Interoperabilità

I Web service offrono una soluzione non proprietaria per la risoluzione di problemi, proprio perché sono spesso offerti al di fuori di una rete privata. Consentono agli sviluppatori di usare il linguaggio di programmazione che preferiscono e sono virtualmente indipendenti dalla piattaforma proprio per l’uso di metodi di comunicazione basati su standard riconosciuti.

Accoppiamento debole (loosely coupled)

Ogni servizio offerto da un Web service esiste indipendentemente dagli altri servizi che insieme costituiscono l’applicazione. Ciò permette di modificare parti dell’applicazione senza impattare in aree che non sono correlate con la parte modificata.

Deployability

I Web service sono messi in opera utilizzando delle tecnologie standard su Internet. Questo permette di effettuare il deploy dei Web service anche remotamente su Internet, e di utilizzare sistemi di sicurezza integrati e comunemente accettati.

A8 Realizzazione di web-service di tipo REST in linguaggio Java

STUDIARE: G. Meini, F. Formichi, Tecnologie di progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2017 pp.225-274.

I principi dell’architettura RESTful

REST definisce un insieme di principi architetturali per la progettazione di un sistema in quanto è uno stile architetturale che specifica come dovrebbe essere scritto un software di interazione in un sistema distribuito che risponda a determinati criteri e principi di funzionamento. REST non fa riferimento ad un sistema concreto e ben definito, e non è uno standard stabilito da un organismo di standardizzazione.

La sua definizione è apparsa per la prima volta nel 2000 nella tesi di Roy Fielding, Architectural Styles and the Design of Network-based Software Architectures, discussa presso l’Università della California, ad Irvine. In questa tesi venivano analizzati alcuni principi alla base di diverse architetture software, tra cui appunto i principi di un’architettura software che consentisse di vedere il Web come una piattaforma per l’elaborazione distribuita.

È bene precisare che i principi REST non sono necessariamente legati al Web, nel senso che si tratta di principi astratti di cui il World Wide Web ne risulta essere un esempio concreto.

All’epoca questa visione del Web non fu adeguatamente considerato, ma negli ultimi anni l’approccio REST è venuto alla ribalta come metodo per la realizzazione di Web Service altamente efficienti e scalabili ed ha al suo attivo un significativo numero di applicazioni.

La ragione per questa inversione di tendenza deriva dal fatto che il Web ha tutto quello che serve per essere considerata una piattaforma di elaborazione distribuita secondo i principi REST, e non sono necessarie altre sovrastrutture per realizzare quello che è il Web programmabile, idea palasemente in conflitto con i Web Service basati su SOAP.

I principi che rendono il Web adatto a realizzare Web Service secondo l’approccio REST possono essere riassunti nei seguenti cinque punti:

  • identificazione delle risorse
  • utilizzo esplicito dei metodi HTTP
  • risorse autodescrittive
  • collegamenti tra risorse
  • comunicazione senza stato

Questi principi rappresentano in realtà concetti ben noti perché ormai insiti nel Web che conosciamo. Li analizzeremo tuttavia sotto una prospettiva diversa, quella della realizzazione di Web Service.

Si osservi che è comunque possibile realizzare Web service utilizzando il protocollo HTTP senza rispettare tutti i principi esposti in precedenza. I Web service che però implementano l’architettura REST in modo integrale sono definiti RESTful.

Analizziamo ora i cinque principi dell’approccio REST elencati precedentemente.

CLIL Listening and Writing- Introduction to Web Services REST

Watch the video REST Web Services 01 - Introduction and answer to the following questions. Send by email your answers to your teacher.

  1. Explain what a Web Service is.
  2. Make a list of the different formats are used by a REST Web Service in order to return a result.
  3. Specify which application protocol is used by REST Web Services in order to exchange data.
  4. Explain how Web Services communication appen.
  5. Explain why a Web Service does not need a service definition.

Identificazione delle risorse

Le risorse sono gli elementi fondamentali su cui si basano i Web Service REST, in netta contrapposizione ai Web Service SOAP-oriented che sono basati sul concetto di chiamata remota.

Per risorsa si intende un qualsiasi elemento oggetto di elaborazione. Per fare qualche esempio concreto, una risorsa può essere un cliente, un libro, un articolo, un qualsiasi oggetto su cui è possibile effettuare operazioni. Per fare un parallelo con la programmazione ad oggetti possiamo dire che una risorsa può essere assimilata ad una istanza di una classe.

Il principio che stiamo analizzando stabilisce che ciascuna risorsa deve essere identificata univocamente. Dato che le interazioni avvengono in ambito Web, il meccanismo più naturale per individuare una risorsa è dato dal concetto di URI.

Il principale beneficio nell’adottare lo schema URI per identificare le risorse consiste nel fatto che esiste già, è ben definito e collaudato e non occorre pertanto inventarsene uno nuovo.

I seguenti sono esempi di possibili identificatori di risorse:

http://www.myapp.com/clienti/1234
http://www.myapp.com/
ordini/2016/98765
http://www.myapp.com/
prodotti/7654
http://www.myapp.com/
ordini/2016
http://www.myapp.com/
prodotti/rosso

Gli URI sono abbastanza autoesplicativi: il primo identifica un determinato cliente, il secondo un ordine e il terzo un prodotto. Il quarto URI identifica l’insieme degli ordini del 2016, mentre l’ultimo URI identifica l’insieme dei prodotti di colore rosso.

L’interpretazione che abbiamo dato a questi URI è però desunta dalla semantica delle parole contenute nelle sue parti. Dal punto di vista di un Web service un URI è soltanto una stringa che identifica una risorsa, per cui anche http://www.myapp.com/tgw34/2099ww può essere un URI valido per identificare un cliente.

CLIL Listening and Writing - REST and HTTP

Watch the video REST Web Services 02 - REST and HTTP and answer to the following questions. Send by email your answers to your teacher.

  1. Describe the main purpose of HTTP.
  2. Explain which Hypertext characteristic is.
  3. Explain what is identified by an URI in a RESTful architecture.
  4. Describe how HTTP methods are used by a RESTful API.
  5. Explain how status codes are used in RESTful architecture.
  6. Specify which header is used to specify the format of data.

CLIL Listening and Writing - Resource URIs

Watch the video REST Web Services 03 - Resource URIs and answer to the following questions. Send by email your answers to your teacher.

  1. Specify which the first thing to design a RESTful API is.
  2. Make an example of a RESTful URI to identify a resource instance.
  3. Specify which is a correct identifier in RESTful URI among nouns and verbs.
  4. Explain why plural is used in RESTful URI.
  5. Explain what “resource relations” represents and give a simple example to manage it.

CLIL Listening and Writing - Collection URIs

Watch the video REST Web Services 04 - Collection URIs and answer to the following questions. Send by email your answers to your teacher.

  1. Make an example of a RESTful URI to identify a collection of resources.
  2. Explain how create a query parameters URI.

Utilizzo esplicito dei metodi HTTP

Una volta spiegato come individuare una risorsa abbiamo bisogno di un meccanismo per indicare quali operazioni effettuare su di esse. Il principio dell’uso esplicito dei metodi HTTP ci indica di usare i metodi predefiniti di questo protocollo, e cioè GET, POST, PUT e DELETE.

Facciamo un semplice esempio per provare a chiarire questo concetto. Quando inseriamo un URI nella barra degli indirizzi di un browser stiamo in realtà chiedendo al browser di eseguire un metodo HTTP sulla risorsa individuata dall’URI. Il metodo che implicitamente stiamo eseguendo è GET, il cui effetto è l’accesso ad una rappresentazione della risorsa identificata dall’URI.

Dal punto di vista del codice, non si avrà bisogno di un metodo del tipo getCliente(1234) per ottenere la rappresentazione del cliente con codice 1234, sarà infatti sufficiente sfruttare il metodo standard GET del protocollo HTTP sull’URI che identifica quel determinato cliente.

Questo rende uniforme l’invocazione di operazioni sulle risorse, cioè il client non ha bisogno di sapere qual è la specifica interfaccia da utilizzare per invocare il metodo che consente di ottenere la rappresentazione di una risorsa. In un contesto non RESTful potremmo avere metodi come getCliente() o getCustomer() o altra specifica dipendente dalle scelte di chi ha sviluppato il Web Service, ma in ambito REST per ottenere lo stato della risorsa basterà usare il metodo GET applicato all’URI che identifica la risorsa stessa.

Quindi in un contesto RESTful l’accesso alla risorsa viene effettuata direttamente con i metodi HTTP, mappando uno a uno le tipiche operazioni CRUD e i metodi HTTP:

Metodo HTTP

Operazione CRUD

Descrizione

POST

Create

Crea una nuova risorsa

GET

Read

Ottiene lo stato di una risorsa esistente

PUT

Update

Aggiorna una risorsa o ne modifica lo stato

DELETE

Delete

Elimina una risorsa

È opportuno notare che questo principio è in contrasto con quella che è la tendenza generale nell’utilizzo dei metodi HTTP. Infatti, molto spesso viene utilizzato il metodo GET per eseguire qualsiasi tipo di interazione con il server. Ad esempio, spesso per l’inserimento di un nuovo cliente nell’ambito di un’applicazione Web viene eseguita una richiesta di tipo GET su un URI del tipo:

http://www.myapp.com/addCustomer?name=Rossi

Questo approccio non è conforme ai principi REST, perchè secondo questo stile architetturale il metodo GET serve per accedere alla rappresentazione di una risorsa e non per crearne una nuova. Nella pratica questo uso del metodo GET introduce un effetto collaterale che può avere delle conseguenze indesiderate se, ad esempio, lo URI viene invocato più volte o se la risorsa viene memorizzata in uno dei vari livelli di cache esistenti tra client e server.

Come principio generale, nel progettare un Web service in modalità REST è utile evitare l’uso di verbi negli URI e limitarsi ad utilizzare nomi, ricordandosi che un URI identifica una risorsa o una collezione di risorse.

Allo stesso modo è opportuno sottolineare che il corpo di una richiesta HTTP con metodi PUT e POST è pensato per il trasferimento della rappresentazione di una risorsa e non per eseguire chiamate remote o altre attività simili.

Per comprendere il principio dell’architettura RESTful per l’accesso alle risorse, si consideri la gestione di una rubrica telefonica. Le operazioni CRUD effettuabili sulla rubrica potrebbero essere esemplificate nel modo seguente.

Creazione (CREATE) di una nuova risorsa Rossi nella rubrica telefonica:

POST http://rubrica.it/
<VoceRubrica>
 
<nominativo>Rossi</nominativo>
 
<telefono>444-555</telefono>
</VoceRubrica>

e in questo caso il server invierà come risposta al client  l’identificativo della nuova voce in rubrica.

Acquisizione (READ) della rappresentazione di una risorsa Rossi dalla rubrica telefonica:

GET http://rubrica.it/Rossi

che restituirà:

<VoceRubrica>
 
<nominativo>Rossi</nominativo>
 
<telefono>444-555</telefono>
</VoceRubrica>

Modifica (UPDATE) di una risorsa Rossi nella rubrica telefonica:

PUT http://rubrica.it/Rossi
<VoceRubrica>
 
<nominativo>Rossi</nominativo>
 
<telefono>444-333 </telefono>
</VoceRubrica>

Cancellazione (DELETE) di una risorsa Rossi dalla rubrica telefonica:

 DELETE http://rubrica.it/Rossi

CLIL Listening and Writing - HTTP Methods

Watch the video REST Web Services 05 - HTTP Methods and answer to the following questions. Send by email your answers to your teacher.

  1. Give an example of an action based URI and an example of a resource based URI.
  2. Describe how it is possible to use the same URI for each CRUD operation in REST Web services.
  3. Give an example for each CRUD operation using the correct HTTP method and an URI to identify a single resource.
  4. Give an example for each CRUD operation using the correct HTTP method and an URI to identify a collection of resources.

Idempotenza dei metodi HTTP

La ragione per cui vengono utilizzati due metodi distinti per effettuare la modifica (PUT) e l’aggiunta (POST) di una risorsa, risiede nel concetto di idempotenza dei metodi HTTP.

Generalmente è possibile classificare i metodi HTTP utilizzati per effettuare operazioni CRUD in due gruppi distinti:

  1. metodi di sola lettura: GET
  2. metodi di scrittura: POST, PUT e DELETE

Alla luce di questa prima classificazione si può dire che il metodo GET, essendo un metodo di sola lettura, può essere ritenuto sicuro; è possibile rieffettuare più volte la stessa richiesta GET sul server senza nessun effetto collaterale, in quanto nulla verrà modificato sul server. Detto in altre parole, il metodo GET è un metodo idempotente, e quindi ripetibile.

L’idempotenza risiede esattamente su questo concetto: un metodo è ritenuto idempotente se è possibile ripetere più volte la stessa richiesta al server senza che vi siano effetti collaterali, tranne eventualmente la prima volta che è stato invocato il metodo.

Dalla definizione di idempotenza segue che anche il metodo PUT è idempotente in quanto, dopo il primo aggiornamento della risorsa, la ripetizione del medesimo aggiornamento non avrà alcun effetto collaterale; eventualmente verrà riscritto più volte il medesimo valore.

Analogamente, il metodo DELETE risulta essere idempotente in quanto, dopo aver cancellato la risorsa identificata da un particolare URI, univoco per ogni risorsa, la ripetizione della medesima cancellazione, usando sempre lo stesso URI, non avrà alcun effetto collaterale.

Invece il metodo POST non è idempotente in quanto la ripetizione della creazione di una risorsa, anche se identica nei contenuti, provocherà l’aggiunta successiva di risorse identificate da URI diversi.

Seguendo il concetto di idempotenza è quindi possibile riclassificare i metodi HTTP utilizzati per effettuare operazioni CRUD nei seguenti due gruppi:

  1. idempotenti (ripetibili in modo sicuro): GET, PUT e DELETE
  2. non idempotenti (non ripetibili in modo sicuro): POST

L’architettura REST richiede esplicitamente che i metodi GET, PUT e DELETE siano idempotenti, mentre il metodo POST deve essere non idempotente.

Il fatto che il metodo GET sia idempotente permette di poter memorizzare nella cache una risposta da parte del server originata da una richiesta GET, e il reinvio ripetuto tramite il refresh del browser non deve avere effetti collaterali. Con il metodo POST, che non è idempotente, si dovrebbe evitare di memorizzare in cache la risposta del server, in quanto il reinvio ripetuto tramite refresh del browser provocherebbe la successiva creazione di nuove risorse sul server.

CLIL Listening and Writing - Method Idempotence

Watch the video REST Web Services 06 - Method Idempotence and answer to the following questions. Send by email your answers to your teacher.

  1. Specify which HTTP methods are read-only and which ones are write methods.
  2. Specify which HTTP methods are safely repeatable and which ones cannot be repeated safely.
  3. Given the previous answers, specify which HTTP methods are safely cacheable and which ones are not safely cacheable.

Risorse autodescrittive

Il concetto di risorse autodescrittive prevede che queste siano  concettualmente separate dalle rappresentazioni restituite al client. Ad esempio, un Web Service non invia al client direttamente un record del suo database, ma una sua rappresentazione in una codifica dipendente dalla richiesta del client e/o dall’implementazione del servizio, ad esempio in XML o in JSON.

I principi REST non pongono nessun vincolo sulle modalità di rappresentazione di una risorsa. Virtualmente è possibile utilizzare il formato che si preferisce senza essere obbligati a seguire uno standard. Di fatto, però, è opportuno utilizzare formati il più possibile standard in modo da semplificare l’interazione con i client. Inoltre, sarebbe opportuno prevedere rappresentazioni multiple di una risorsa, per soddisfare client di tipo diverso, ad esempio sia in XML, sia in JSON.

Il tipo di rappresentazione inviata dal Web service al client è indicato nella stessa risposta HTTP tramite un tipo MIME, così come avviene nella classica comunicazione tra Web server e browser, utilizzando lo header HTTP Content-type.

Un client a sua volta ha la possibilità di richiedere una risorsa in uno specifico formato sfruttando l’attributo Accept di una richiesta HTTP, come mostrato nel seguente esempio:

GET /clienti/1234
HTTP/1.1
Host: www.myapp.com
Accept: text/xml

In questo caso il client richiede la rappresentazione del cliente identificato dal codice 1234 in formato XML. Ovviamente, se il Web service supportasse ulteriori formati, la stessa risorsa potrebbe essere richiesta in formati diversi, come ad esempio in JSON o in HTML.

La possibilità di rappresentazioni multiple produce alcuni benefici pratici: ad esempio, se abbiamo un output sia in HTML, sia in XML, possiamo consumare il servizio sia con un’applicazione sia con un comune browser. In altre parole, seguendo i principi REST nel progettare un’applicazione Web è possibile costruire sia una Web API che una Web UI.

CLIL Listening and Writing - REST Response

Watch the video REST Web Services 07 - REST Response and answer to the following questions. Send by email your answers to your teacher.

  1. Explain the reason for which REST Web services use different representations of resources.
  2. Describe for which purpose is used the HTTP header Content Type in a HTTP response.
  3. Describe the purpose of a status code in a HTTP response.
  4. List all the status code groups giving a brief explanation for each of them.
  5. Give an example for each CRUD operations of a suitable status code and explaining string sent by the server in its response.

Collegamenti tra risorse e il principio HATEOAS

Un altro vincolo dei principi REST consiste nella necessità che le risorse siano tra loro messe in relazione tramite link ipertestuali. Questo principio è anche noto come HATEOAS, dall’acronimo di Hypermedia As The Engine Of Application State, e pone l’accento sulle modalità di gestione dello stato dell’applicazione.

In sostanza questo principio afferma che tutto quello che un client deve sapere su una risorsa, e sulle risorse ad essa correlate, deve essere contenuto nella rappresentazione della risorsa stessa o deve essere accessibile tramite collegamenti ipertestuali.

Ad esempio, la rappresentazione di un ordine in un linguaggio XML-based deve contenere gli eventuali collegamenti al cliente e agli articoli correlati:

<ordine>
 
<numero>12345678</numero>
 
<data>01/07/2011</data>
 
<cliente rif="http://www.myapp.com/clienti/1234" />
 
<articoli>
   
<articolo rif="http://www.myapp.com/prodotti/98765" />
   
<articolo rif="http://www.myapp.com/prodotti/43210" />
 
</articoli>
</ordine>

In questo modo il client può accedere alle risorse correlate seguendo semplicemente i collegamenti contenuti nella rappresentazione XML della risorsa corrente.

Il fatto di utilizzare un URI come identificatore di una risorsa, quindi un meccanismo standard e consolidato, consente al client di accedere anche a risorse messe a disposizione da altre applicazioni, che potrebbero trovarsi eventualmente su altri server.

L’architettura REST (REpresentational State Transfer) enfatizza proprio il concetto di trasferimento di stato, cioè il fatto che un’applicazione possa passare velocemente da uno stato all’altro. Nell’architettura REST lo stato di una applicazione è rappresentato dallo stato delle sue risorse e, grazie al principio HATEOAS, la relativa transazione di stato delle risorse viene attivata attraverso l’uso di semplici collegamenti ipermediali.

Nella visione REST l’esecuzione di un’applicazione può quindi essere rappresentata da una rete di risorse fra cui un client “naviga” seguendo i collegamenti ipermediali ammessi tra una risorsa e l’altra. Questa visione richiama esattamente la navigazione tra pagine Web diverse, visitabili tramite link.

Il principio HATEOAS cerca di incoraggiare l’uso di collegamenti ipermediali sia per rappresentare risorse composte, sia per definire qualsiasi altra relazione tra le risorse e per controllare le transizioni ammissibili tra uno stato e l’altro dell’applicazione.

Per fare un esempio, consideriamo la seguente rappresentazione di un ordine in un ipotetico negozio online :

<ordine id=”123” data=”10/03/2017”>
 
<cliente>Mario Rossi</cliente>
 
<stato>EVASO</stato>
 
<dettagli>
   
<dettaglio>
     
<articolo>Libro</articolo>
     
<quantita>1</quantita>
   
</dettaglio>
   
<dettaglio>
     
<articolo>CD</articolo>
     
<quantita>5</quantita>
   
</dettaglio>
 
</dettagli>
</ordine>

In esso non è riportato alcun collegamento con altre risorse gestite dal sistema. Affinché un cliente possa risalire alla fattura associata a questo ordine dovrà effettuare un’apposita richiesta al Web Service, utilizzando l’URI della risorsa fattura che il cliente dovrebbe procurarsi in qualche modo. Nell’ottica del principio HATEOAS sarebbe opportuno includere un collegamento direttamente nella rappresentazione dell’ordine:

<ordine id=”123” data=”10/03/2017”>
 
<cliente>Mario Rossi</cliente>
 
<stato>EVASO</stato>
 
<dettagli>
   
<dettaglio>
     
<articolo>Libro</articolo>
     
<quantita>1</quantita>
   
</dettaglio>
   
<dettaglio>
     
<articolo>CD</articolo>
     
<quantita>5</quantita>
   
</dettaglio>
 
</dettagli>

  <links>

      <link rel="self"  mediaType="application/xml"
         
href="http://www.mionegozio.com/ordini/123" />
     
<link rel="fattura" mediaType="application/xml"
         
href="http://www.mionegozio.com/fatture/789" />

  </links>
</ordine>

In questo modo il client ha già nella rappresentazione dell’ordine tutte le informazioni necessarie per accedere sia all’ordine (self), sia alla fattura associata. Inoltre, la presenza o meno del collegamento alla fattura associata all’ordine fornisce implicitamente un’altra informazione al client: se il collegamento non è presente nella rappresentazione dell’ordine vuol dire che la fattura non è ancora stata emessa, se invece è presente vuol dire che è stata emessa ed è accessibile. In questo modo si avrà un maggior controllo della transizione da uno stato all’altro dell’applicazione, evitando transizioni non ammissibili in un dato momento.

Sfruttando pienamente il principio HATEOAS è possibile creare servizi Web con accoppiamento debole tra client e server. Infatti, se il server riorganizza le relazioni tra le risorse, il client è in grado di trovare tutto ciò che serve nelle rappresentazioni ricevute. Potenzialmente tutto quello che servirebbe ad un client è solo l’URI della risorsa iniziale, ad esempio quello dell’ordine. Come avanzare tra uno stato e l’altro dell’applicazione verrà indicato man mano che si seguono i collegamenti incorporati nelle successive rappresentazioni delle risorse.

Il principio HATEOAS, che sancisce il legame tra transizioni di stato e collegamenti tra risorse, è purtroppo scarsamente sfruttato nelle attuali implementazioni di Web service di tipo REST. La maggior parte di queste implementazioni si limita a definire le rappresentazioni delle risorse e le modalità di interazione tramite i metodi HTTP, non sfruttando a pieno le potenzialità dei principi REST.

CLIL Listening and Writing - HATEOAS

Watch the video REST Web Services 08 - HATEOAS and answer to the following questions. Send by email your answers to your teacher.

  1. From the client point of view, explain which is the purpose of using an URI inside an XML file received from a server.
  2. Specify which kind of element can be used in a XML file to identify a resource URI.
  3. Explain which is the purpose of the href and rel attributes.
  4. Suppose it is necessary to create an XML file to describe the books in a library. For each book it is important to store in the XML file the library identification, the title, the author’s name, the publisher and the year when the book was published. Create an example of the XML file using the HATEOAS principle.

Comunicazione senza stato

Il principio della comunicazione stateless è ben noto a chi lavora con il Web. Questa è infatti una delle caratteristiche principali del protocollo HTTP, cioè ciascuna richiesta non ha alcuna relazione con le richieste precedenti e successive.

Lo stesso principio si applica ad un Web service REST, cioè le interazioni tra client e server devono essere senza stato, rendendo ciascuna richiesta indipendente dalle altre.

La comunicazione stateless prevede che una richiesta effettuata dal client non richieda al server il recupero dello stato dell’applicazione o di un suo contesto. Il Web service o il client REST devono includere nelle intestazioni o nel corpo HTTP tutti i parametri, il contesto e i dati necessari al server per generare una risposta.

È importante sottolineare che sebbene REST preveda la comunicazione stateless, non vuol dire che un’applicazione non debba avere uno stato. Ciò che si richiede è che la responsabilità della gestione dello stato dell’applicazione non debba essere conferita al server, ma deve rientrare nei compiti del client.

La principale ragione di questa scelta è la scalabilità: mantenere lo stato di una sessione ha un costo in termini di risorse sul server e, all’aumentare del numero di client, tale costo può diventare insostenibile.

Inoltre, con una comunicazione senza stato è possibile creare cluster di server che possono rispondere ai client senza vincoli sulla sessione corrente, ottimizzando le prestazioni globali dell’applicazione.

Infine una comunicazione senza stato consente di ottimizzare le prestazione del Web service e di semplificare la progettazione e l’implementazione lato server, dato che l’assenza della gestione dello stato rimuove la necessità di sincronizzare i dati di sessione con una applicazione esterna.

Il protocollo HTTP è intrinsecamente senza stato, ma molto spesso, nello sviluppo di applicazioni Web, vengono artificialmente ricreate le condizioni per una comunicazione con stato. Ad esempio, l’uso di chiavi di sessione, utilizzate in diversi framework di sviluppo per il Web, non fa altro che introdurre lo stato della comunicazione al di sopra del protocollo HTTP, in genere sfruttando i cookie.

In una architettura REST l’uso di comunicazioni con stato sarebbe vietato; il server non dovrebbe tenere traccia delle relazioni tra le diverse richieste. Se fosse necessario gestire uno stato della comunicazione, questo compito spetterebbe completamente al client.

Stato delle risorse e dell’applicazione

Il fatto che i principi REST escludano la gestione dello stato della comunicazione non deve però far pensare che i Web Service REST siano senza stato. L’acronimo REST sta per REpresentational State Transfer, sottolineando proprio la centralità della gestione dello stato in un sistema distribuito. Lo stato che REST prende in considerazione è però quello delle risorse e dell’intera applicazione, come enfatizzato in precedenza relativamente al principio HATEOAS.

Lo stato delle risorse è dato dall’insieme dei valori che caratterizzano una risorsa in un dato momento. Un Web Service è responsabile della gestione dello stato delle risorse. Un client può accedere allo stato di una risorsa tramite le diverse rappresentazioni della risorsa stessa utilizzando il metodo GET di HTTP, e contribuire a modificarlo per mezzo dei metodi PUT, POST e DELETE di HTTP.

Lo stato del client è rappresentato dall’insieme del suo contesto e delle risorse ottenute in uno specifico momento. Il server può influenzare le transizioni di stato del client inviando differenti rappresentazioni delle risorse in risposta alle sue richieste.

Lo stato dell’applicazione, cioè del risultato dell’interazione tra client e server, è dato dallo stato del client e delle risorse gestite dal server, e determina le modalità di modifica dello stato delle risorse e del client. A differenza di quanto avviene in buona parte delle applicazioni Web, dove lo stato dell’applicazione viene spesso mantenuto dal server insieme allo stato della comunicazione, lo stato dell’applicazione in un’architettura REST è il frutto della collaborazione di client e server, ciascuno con i propri ruoli e responsabilità. Nella progettazione di un Web Service REST questa separazione dei ruoli deve essere chiara e spesso occorre ripensare opportunamente la gestione dello stato in termini di gestione di risorse.

Ad esempio, per gestire un carrello in una comune applicazione Web di e-commerce, si ricorre tipicamente ad una sua rappresentazione lato server associata alla sessione corrente dell’utente. Per quanto abbiamo detto finora, questo approccio viola i principi REST dal momento che richiede il mantenimento dello stato della sessione. Per rimanere nell’ambito dei principi REST abbiamo a disposizione due possibili soluzioni: demandare al client il compito di gestire il carrello, o gestire il carrello sul server come una risorsa.

Nel primo caso il client avrà una struttura dati in cui terrà traccia degli articoli a cui l’utente è interessato. Nel momento della generazione della richiesta di un nuovo ordine da inviare al server, gli articoli annotati nel carrello verranno riportati nell’ordine.

In alternativa è possibile che il nostro Web Service preveda una risorsa carrello dedicata al mantenimento degli articoli scelti dall’utente durante la fase di acquisto. È da sottolineare il fatto che il carrello è una risorsa come le altre e non è associata alla sessione corrente. È quindi accessibile tramite URI in qualsiasi momento, è persistente ed è gestibile tramite i metodi HTTP.

La trasformazione in risorse di elementi tradizionalmente gestiti tramite lo stato della sessione, è un approccio da tenere presente durante la progettazione di un Web Service REST.

CLIL Listening - The Richardson Maturity Model

Watch the video REST Web Services 09 - The Richardson Maturity Model to complete your theoretical preparation about Web Service RESTful.


CLIL Listening - Developing RESTful APIs with JAX-RS

The following video are optional material and the subject is not part of the course o this year. If you would like to improve your understanding about RESTful APIs development using JAX-RS, watch the following video.


REST e sicurezza HTTP (cenni)

Uno degli aspetti cruciali di qualsiasi applicazione Web è la gestione della sicurezza. I Web service REST, rendendo accessibili le risorse tramite i meccanismi del Web, non possono sottrarsi a questa necessità.

In linea di massima la sicurezza di un sistema coinvolge almeno i seguenti aspetti:

  • l’autenticazione, cioè la capacità di identificare le parti coinvolte in una comunicazione
  • l’autorizzazione, cioè la concessione dei diritti di accesso ad una risorsa in base all’identità
  • la fiducia, cioè la capacità di confidare nel risultato di un’operazione, come ad esempio l’autenticazione o l’autorizzazione, eseguita da terze parti
  • la riservatezza, cioè la capacità di mantenere l’informazione privata durante la trasmissione o la memorizzazione
  • l’integrità, cioè la capacità di prevenire che l’informazione possa essere modificata da terzi

Nel Web tutti questi aspetti sono stati efficacemente affrontati da diverso tempo, rendendo il modello sufficientemente maturo per decidere di gestire la sicurezza dei Web service REST basandosi largamente sul protocollo HTTP, ereditandone le caratteristiche ormai ampiamente collaudate.

In sostanza, per gestire l’identità nell’ambito di un Web Service REST possono essere utilizzati i meccanismi propri del protocollo HTTP, come ad esempio HTTP Basic Authentication o HTTP Digest Authentication.

Ad esempio, se un client richiede l’accesso ad una risorsa protetta, il server può richiedere l’autenticazione con una risposta HTTP analoga alla seguente:

401 Unauthorized
WWW-Authenticate:
Basic realm="risorsaRiservata"

La risposta richiede di autenticarsi utilizzando HTTP Basic Authentication. Il client invierà una risposta di questo tipo:

GET /ordini/?123 HTTP/1.1
Host: www.mionegozio.com
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

dove le credenziali di autenticazione vengono passate sotto forma di stringa codificata in Base64.

Da questo momento in poi, rispettando le caratteristiche dell’architettura REST, ciascuna richiesta successiva inviata al server conterrà queste credenziali,  mantenendo la natura stateless delle comunicazione HTTP.

Naturalmente l’invio delle credenziali con la semplice codifica Base64 non è sufficiente garanzia di riservatezza. L’uso di HTTP Digest Authentication è sicuramente un passo avanti per evitare la trasmissione in chiaro della password, ma non è esente da possibili attacchi.

La soluzione che in genere andrebbe adottata consiste nella creazione di un canale di trasmissione sicuro, come può essere HTTPS, cioè HTTP over SSL/TLS. L’adozione di HTTPS garantisce la riservatezza e l’integrità nella trasmissione delle informazioni, coprendo gli altri aspetti di sicurezza.

Sicurezza con “sessioni REST” e tramite servizi di terze parti (cenni)

Nel caso in cui i meccanismi di sicurezza propri del protocollo HTTP non siano sufficienti o adeguati per il tipo di Web Service da sviluppare, è sempre possibile gestire la sicurezza in modo personalizzato. In genere questo accade per la gestione dell’autenticazione e dell’autorizzazione dei client, dove i criteri possono essere diversi in base allo specifico dominio del problema.

Non c’è un obbligo nell’utilizzare i meccanismi standard del protocollo HTTP, ma è bene sottolineare che ogni eventuale soluzione personalizzata dovrebbe rispettare i principi REST. Infatti il rischio di cadere in una soluzione non-REST per gestire l’autenticazione e l’autorizzazione dei client è alto, dal momento che di solito si tenterebbe di introdurre nuovamente il concetto di sessione associata al client appena autenticato.

In realtà il problema non sta nel concetto di sessione, ma nella modalità di gestione. Dal momento che REST non ammette il mantenimento dello stato della sessione tra una richiesta e le altre, occorre che il client e il server si scambino tutte le informazioni necessarie per ricreare la sessione ad ogni interazione. Questo vuol dire rigenerare la sessione ad ogni richiesta utilizzando le credenziali fornite dal client, con potenziale perdita di prestazioni, anche se i criteri di autenticazione ed autorizzazione non sono molto complessi.

Lo stato come risorsa

Un’alternativa potrebbe essere trasformare la sessione in risorsa, utilizzando un approccio analogo a quello adottato per l’implementazione del carrello del negozio online visto in precedenza. L’autenticazione di un client corrisponde alla richiesta di creazione di una risorsa di tipo sessione: se le credenziali fornite dal client sono valide, allora viene creata la risorsa ed inviato il corrispondente URI al client, che da questo momento in poi lo invierà al server con ogni richiesta.

Ad ogni richiesta il server recupererà la sessione per effettuare le necessarie verifiche e in caso positivo soddisferà le richieste del client.

Il server avrà la responsabilità di gestire opportunamente la sessione, come ad esempio eliminarla dopo un determinato periodo di inattività, ma non la manterrà in memoria, la gestirà come una normale risorsa persistente.

OpenID e OAuth: gestione esterna della sicurezza

Come è possibile immaginare, la gestione dell’autenticazione e dell’autorizzazione dei client rischia di complicare la progettazione e l’implementazione di un Web Service. Una soluzione potrebbe essere quella di delegare ad un servizio esterno il compito di gestire i client, utilizzando un Web Service specializzato nella gestione dell’autenticazione e/o dell’autorizzazione.

Negli ultimi tempi sono venuti alla ribalta servizi aperti che si pongono proprio l’obiettivo di decentralizzare la gestione di alcuni aspetti della sicurezza. Tra i servizi di questo tipo i più noti e diffusi nell’ambito della realizzazione di Web Service REST sono OpenID e OAuth.

OpenID è un protocollo per la gestione dell’identità online. Esso consente ad un client di presentare ad un Web Service o ad un sito Web un URI come dichiarazione della propria identità. L’applicazione Web chiede conferma della validità al relativo servizio di autenticazione (OpenID provider) il quale, dopo aver interagito con il client, conferma o smentisce l’autenticità dell’identità dichiarata.

OAuth è un protocollo per la concessione a terze parti di autorizzazioni per l’accesso a risorse protette. In pratica, un client può consentire ad un Web Service l’accesso ad una risorsa protetta, ospitata da un service provider, senza fornire le proprie credenziali.

È naturale che l’utilizzo di servizi esterni per la gestione di alcuni aspetti della sicurezza presuppone che il Web Service riponga piena fiducia nel fornitore del servizio, senza la quale questo tipo di servizi non avrebbero senso.


Esempi di Web service di tipo REST in linguaggio Java

Calcolatrice REST

La seguente servlet Java realizza un semplice Web service che implementa una calcolatrice che restituisce il risultato di operazioni aritmetiche. La richiesta avviene mediante URL che terminano con una query string costituita da due valori numerici (op1 per il primo operando e op2 per il secondo operando) e l’operazione da effettuare (add per la somma, sub per la sottrazione, mul per la moltiplicazione e div per la divisione assegnati al parametro operation).

La query string viene costruita automaticamente compilando un form iniziale.

Il codice per generare il form è il seguente.

<%--
        
Document   : index
        
Created on : 21-feb-2017, 8.51.35
        
Author         : docente
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
 
<head>
           
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
           
<title>JSP Page</title>
 
</head>
 
<body>
           
<form action="getxml" method="get">
               
<input type="number"  name="op1"/><br />
               
<input type="number"  name="op2"/><br />
               
<input type="radio" name="operation" value="add" checked/>ADD
               
<input type="radio" name="operation" value="sub" />SUB
               
<input type="radio" name="operation" value="mul" />MUL
               
<input type="radio" name="operation" value="div" />DIV <br />
               
<input type="submit"  value="Invia"/>
               
<input type="reset"  value="Cancella"/>
           
</form>
 
</body>
</html>

Selezionando l’operazione add verrà generato il seguente URL di richiesta:

http://localhost:8080/ArithmeticOperations/getxml?op1=5&op2=6&operation=add

ottenendo il seguente risultato in formato XML.

Gli URL generati in corrispondenza delle altre possibili richieste corrisponderebbero ai seguenti:

http://localhost:8080/ArithmeticOperations/getxml?op1=5&op2=6&operation=sub
http://localhost:8080/ArithmeticOperations/getxml?op1=5&op2=6&operation=mul
http://localhost:8080/ArithmeticOperations/getxml?op1=5&op2=6&operation=div

L’identificazione delle risorse utilizzato negli URI di questo Web service potrebbero apparire in contrasto con i principi RESTful. La presenza di parametri nello URI potrebbe far pensare ad una chiamata di procedura piuttosto che ad un identificatore di risorsa.

In realtà l’approccio è comunque legittimo nell’ambito dell’architettura REST in quanto la stringa è univoca ed identifica esattamente la risorsa che vogliamo ottenere senza alcun effetto collaterale. La presenza dei parametri ci dà la sensazione di una chiamata di procedura, ma da un punto di vista REST non si tratta che di una sequenza di caratteri per l’identificazione di una risorsa.

L’implementazione del Web service che genera la risposta XML con il risultato dell’operazione aritmetica, è realizzato utilizzando la servlet mostrata di seguito. Nella servlet non è stato utilizzato il deployment descriptor web.xml per configurare la servlet, bensì si è preferito utilizzare le annotazioni di Java.

L’annotazione @WebServlet permette di impostare il nome della servlet attraverso l’elemento name (WriteXml), mentre l’URL di invocazione della servlet viene impostato attraverso l’elemento urlPatterns (/getxml). Se in quest’ultimo elemento fosse stato impostato il valore /* si sarebbe potuto associare all’invocazione della servlet una qualsiasi sezione finale dell’URL, permettendo al codice della servlet stessa di modificare la propria risposta in base all’analisi della struttura dello URL.

import application.Application;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
*
*
@author docente
*/

@WebServlet(name = "WriteXml", urlPatterns = {"/getxml"})
public class WriteXml extends HttpServlet {

 
/**
  * Processes requests for both HTTP <code>GET</code> and

   * <code>POST</code> methods.
  *
  *
@param request servlet request
  *
@param response servlet response
  *
@throws ServletException if a servlet-specific error occurs
  *
@throws IOException if an I/O error occurs
  */

 
protected void processRequest(HttpServletRequest request,

          HttpServletResponse response) throws ServletException, IOException {
           response.setContentType(
"text/xml;charset=UTF-8");
           PrintWriter out = response.getWriter();
           String result =
"";
           String status =
"400";
           String operation =
"";
           String op1 =
"";
           String op2 =
"";
           
int op1Int = 0;
           
int op2Int = 0;
           
try {
               op1 = request.getParameter(
"op1");
               op2 = request.getParameter(
"op2");
               operation = request.getParameter(
"operation");
               
if (op1 == null || op2 == null || op1.trim().isEmpty() ||

                op2.trim().isEmpty()) {
                   result =
"ERRORE";
               }
else {
                   op1Int = Integer.parseInt(op1);
                   op2Int = Integer.parseInt(op2);

                  /**
                  * La classe Application svolgerà l’operazione aritmetica

                   * richiesta.
                  */

                   Application app =
new Application();
                   result =
"" + app.getResult(operation, op1Int, op2Int);
                   status =
"200";
               }

           }
catch (NumberFormatException ex) {
               result=
"ERRORE";
           }
finally {
               out.println(
"<response>");
               out.println(
"<statuscode>");
               out.println(status);
               out.println(
"</statuscode>");
               out.println(
"<op1>");
               out.println(op1);
               out.println(
"</op1>");
               out.println(
"<op2>");
               out.println(op2);
               out.println(
"</op2>");
               out.println(
"<operation>");
               out.println(operation);
               out.println(
"</operation>");
               out.println(
"<value>");
               out.println(result);
               out.println(
"</value>");
               out.println(
"</response>");
           }
 }

 
/**
  * Handles the HTTP <code>GET</code> method.
  *
  *
@param request servlet request
  *
@param response servlet response
  *
@throws ServletException if a servlet-specific error occurs
  *
@throws IOException if an I/O error occurs
  */

 
@Override
 
protected void doGet(HttpServletRequest request,

          HttpServletResponse response) throws ServletException, IOException {
           processRequest(request, response);
 }

 
/**
  * Handles the HTTP <code>POST</code> method.
  *
  *
@param request servlet request
  *
@param response servlet response
  *
@throws ServletException if a servlet-specific error occurs
  *
@throws IOException if an I/O error occurs
  */

 
@Override
 
protected void doPost(HttpServletRequest request,

          HttpServletResponse response) throws ServletException, IOException {
           processRequest(request, response);
 }

 
/**
  * Returns a short description of the servlet.
  *
  *
@return a String containing servlet description
  */

 
@Override
 
public String getServletInfo() {
           
return "Arithmetic operations";
 }
}

La classe Application svolge l’operazione aritmetica richiesta.

/**
*
*
@author docente
*/

public class Application {
   
 
public int getResult(String operation, int op1, int op2){
           
int result=0;
           
switch(operation){
               
case "add": result=op1+op2; break;
               
case "sub": result=op1-op2; break;
               
case "mul": result=op1*op2; break;
               
case "div": result=op1/op2; break;
           }
           
return result;
 }
}

Per configurare la servlet si sarebbe potuto utilizzare il deployment descriptor web.xml riportato di seguito.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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/web-app_3_1.xsd"
>
        
<servlet>
               
<servlet-name>WriteXml</servlet-name>
               
<servlet-class>WriteXml</servlet-class>
        
</servlet>
        
<servlet-mapping>
               
<servlet-name>WriteXml</servlet-name>
               
<url-pattern>/getxml</url-pattern>
        
</servlet-mapping>
        
<session-config>
               
<session-timeout>
                 30
               
</session-timeout>
        
</session-config>
</web-app>


Web service per operazioni CRUD su database

Per rendere persistenti le risorse esposte da un Web service può essere utilizzato un database relazionale gestito da un DBMS, implementando in questo modo una architettura a tre livelli:

  1. il Presentation layer che presenterà al client l’interfaccia per poter accedere alla risorsa, utilizzando i metodi offerti dal gestore della risorsa;
  2. il Business logic layer costituito dal Web server o Application server che riveste il ruolo di container ed esegue la servlet che implementa il Web service;
  3. il Resource Management layer costituito dal server DBMS che gestisce i dati memorizzati in modo persistente.

Un’architettura di questo tipo, definita three-tier, garantisce un ampio disaccoppiamento tra i vari elementi del sistema software, permettendo una diversa gestione della sicurezza sui diversi layer, rendendoli facilmente scalabili e manutenibili e permettendo aggiornamenti mirati per ogni tier.

JDBC e MySQL

P. Camagni, R. Nikolassy, Tecnologie e progettazione di sistemi informatici e di telecomunicazioni, vol. 3, ed. Hoepli, 2014, pp.212-213 e pp.215-218.

  • JDBC
  • Lavorare con JDBC
  • Servlet con connessione a MySQL

P. Camagni, R. Nikolassy, Tecnologie e progettazione di sistemi informatici e di telecomunicazioni, vol. 3, ed. Hoepli, 2014, pp.250-254.

  • Lab. 5 - JDBC e MySQL
ShowRoom REST su database

Il seguente esempio mostra alcune funzionalità di un Web service REST che manipola i dati di un database (EsempioREST) di prodotti (Products) venduti presso diversi negozi (Showrooms) di una catena commerciale. I prodotti sono organizzati per categorie (Categories). Il Web service permetterà di interrogare il database utilizzando esclusivamente i metodi HTTP e un URL che identifichi la risorsa, come richiesto dall’architettura REST.

Il server SimpleRestDb è stato creato in modo tale da presentare all’avvio le modalità di costruzione degli URL per poter effettuare una richiesta di visualizzazione del contenuto di una tabella del database EsempioREST. Questa leggenda, fornita in formato XML, permetterà di effettuare la visualizzazione dei contenuti delle singole tabelle del database, sia globalmente, sia in modo parametrico usando un identificatore.

Ad esempio, per visualizzare tutti i prodotti presenti nella tabella Products del database EsempioREST si dovrà utilizzare lo URL:

http://localhost:8080/SimpleRestDb/products

Il metodo GET invocato con questo URL verrà gestito dal Web service tramite il metodo doGet() che, effettuando un’analisi dello URL, selezionerà la visualizzazione di tutti i prodotti. Nell’immagine seguente viene riportata una porzione della risposta XML restituita dal Web service.

Invece, effettuando la richiesta di un singolo prodotto tramite il suo id utilizzando il seguente URL

http://localhost:8080/SimpleRestDb/product/5

si otterrà la visualizzazione del singolo prodotto, sempre in formato XML.

Per testare le operazioni di aggiunta (CREATE - POST), aggiornamento (UPDATE - PUT) e cancellazione (DELETE - DELETE) di una istanza, verrà utilizzato un semplice client, RestClient.

Nel seguito della trattazione verrà fornita una possibile implementazione del database, del Web service e del client.

Database EsempioREST

Lo schema concettuale, semplificando la realtà gestita, è il seguente:

schema concettuale.png

Analizzando lo schema E-R (concettuale) si deduce:

  • un prodotto dell’entità Products è presente in una sola categoria dell’entità Categories e l’occorrenza è obbligatoria, cioè un prodotto non può essere privo di categoria;
  • una categoria dell’entità Categories può contenere più prodotti, ma vista la cardinalità minima pari a zero di partecipazione alla relazione inCategory, una categoria potrebbe anche non avere prodotti (ad esempio quando una categoria è stata appena creata e nessun prodotto è stato ancora associato alla categoria);
  • un prodotto dell’entità Products è venduto da almeno un negozio dell’entità Showrooms e l’occorrenza è obbligatoria, cioè un prodotto non può non essere venduto almeno in un negozio;
  • un negozio dell’entità Showrooms può vendere più prodotti, ma vista la cardinalità minima pari a zero di partecipazione alla relazione ProductsShowrooms, un negozio potrebbe anche non avere prodotti in vendita (ad esempio quando un negozio è stato appena aperto e nessun prodotto è stato ancora associato al negozio);

Lo schema logico sarà il seguente:

Categories(id, description)

Products(id, name, description, price, id_category)

Showrooms(id, name, address, city, phone, site)

ProductsShowrooms(id_products, id_showroom)

Il DDL e DML della relativa progettazioe fisica per la creazione del database, delle tabelle e della relativa popolazione delle stesse, sarà il seguente:

-- phpMyAdmin SQL Dump
-- version 4.5.4.1deb2ubuntu2
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: Mar 28, 2017 at 09:59 PM
-- Server version: 5.7.17-0ubuntu0.16.04.1
-- PHP Version: 7.0.15-0ubuntu0.16.04.4

SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;

--
-- Database: `EsempioRest`
--
CREATE DATABASE IF NOT EXISTS `EsempioRest` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `EsempioRest`;

-- --------------------------------------------------------

--
-- Table structure for table `Categories`
--

CREATE TABLE `Categories` (
 
`id` int(11) NOT NULL,
 
`description` varchar(50) NOT NULL
)
ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- RELATIONS FOR TABLE `Categories`:
--

--
-- Dumping data for table `Categories`
--

INSERT INTO `Categories` (`id`, `description`) VALUES
(
1, 'Informatica e telefonia'),
(
2, 'TV e audio'),
(
3, 'Fotografia, Auto e Navi'),
(
4, 'Grandi Elettrodomestici'),
(
5, 'Piccoli Elettrodomestici'),
(
6, 'Gaming, Musica e Film'),
(
7, 'Innovazione'),
(
8, 'Tempo Libero'),
(
9, 'Outlet');

-- --------------------------------------------------------

--
-- Table structure for table `Products`
--

CREATE TABLE `Products` (
 
`id` int(11) NOT NULL,
 
`name` varchar(50) NOT NULL,
 
`description` varchar(500) DEFAULT NULL,
 
`price` float(5,2) NOT NULL,
 
`id_category` int(11) NOT NULL
)
ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- RELATIONS FOR TABLE `Products`:
--   `id_category`
--           `Categories` -> `id`
--

--
-- Dumping data for table `Products`
--

INSERT INTO `Products` (`id`, `name`, `description`, `price`, `id_category`) VALUES
(
1, 'ASUS F540YA-XO260T Chocolate Black', 'Processore AMD A8-Series-A8-7410 (2,2 GHz - 2 MB L2)\r\nHDD: 500 GB - RAM: 8 GB - Display: 15,6\'\' LED\r\nWiFi IEEE 802.11a/b/g - Bluetooth 4.0 - Windows 10\r\nScheda grafica AMD Radeon R5 Condivisa', 399.99, 1),
(
2, 'EPSON V11H664040 ', 'Videoproiettore con Tecnologia 3LCD\r\nContrasto di immagine: 15.000:1\r\nLuminosità 3000 Ansi Lumen\r\nRisoluzione: 1280x800 pixel\r\nImmagini brillanti in 2D e 3D', 449.99, 2),
(
3, 'HOTPOINT FMG 723 B IT.M ', 'Lavatrice - Carica: Frontale - Tipo installazione: Libera installazione (FS) - Classe energetica: A +++ - Capacità max carico: 7 kg - Velocità max centrifuga: 1.200 giri/min - Profondità: 52,2 cm', 279.99, 4),
(
4, 'HP 15-AC195NL - PRMG GRADING OOAN - SCONTO 10,00% ', 'Processore Intel® Core™ i7-5500U(2,4/3GHz - 4MB L3)\r\nHDD 1000 GB - RAM 8GB - Display 15,6" WLED HD Ready\r\nWi-Fi 802.11b/g/n - Windows 10\r\nScheda grafica AMD Radeon R5 M330(2GB Dedicata)\r\nPRODOTTO RICONDIZIONATO - PRMG GRADING  OOAN\r\nConfezione originale  integra (O)\r\nAccessori principali  presenti (O)\r\nEstetica prodotto  come nuovo (A)\r\nStato prodotto  funzionante (N)', 719.99, 9),
(
5, 'APPLE MacBook Air 13" MMGF2T/A ', 'Processore Intel® Core i5 Dual-Core (1.60/2.70GHz, 3MB L3)\r\nHD 128GB SSD - RAM 8GB - Display 13.3" widescreen lucido LED\r\nWi-Fi 802.11a/b/g/n/ac - Bluetooth 4.0 - Mac OS X El Capitan\r\nScheda grafica Intel® HD Graphics 6000', 899.99, 1),
(
6, 'BRONDI FX-Compact Sport S ', 'Frequenza PMR - 8 Canali\r\n38 Codici per canali - Funzione VOX\r\nFunziona con 3 ministilo alcaline\r\nComunica con tutte le ricetrasmittenti PMR446', 19.99, 8),
(
7, 'MAJESTIC SD 247 RDS USB AX ', 'Digital Media Receiver Mechaless - Potenza 4x30W\r\nLettura MP3, WMA - Display ID3 Tag\r\nSintonizzatore RDS\r\nIngresso AUX - USB - SD/MMC Card', 34.99, 3),
(
8, 'SONY KD43XD8099B ', 'SMART TV LED 43" Ultra HD 4K - Risoluzione: 3840x2160\r\nTecnologia 400Hz - DLNA - Wi-fi\r\nTuner Digitale Terrestre DVB-T2 HEVC e Satellitare DVB-S\r\nProcessore Video 4K X-Reality Pro\r\nClasse efficienza energetica: B\r\nDistribuito da Sony Italia', 749.99, 2),
(
9, 'PANASONIC RP-WF830E-K ', 'Cuffie Stereo Wireless\r\nRisposta in frequenza 18-22.000 Hz\r\nDistanza di trasmissione fino a 100 m', 54.99, 2),
(
16, ' BOSCH PCQ715B90E ', 'Piano cottura - 5 Fuochi gas - Accensione ad 1 mano\r\nTermosicurezza - 2 Griglie in ghisa - Comandi frontali\r\nLarghezza: 70 cm', 299.99, 4),
(
17, 'LENOVO Ideapad 110-15ISK', 'Processore Intel® Core™ i5-6200U(2.3/2.8GHz, 3MB L2)\r\nHDD 500 GB - RAM 4GB - Display 15,6" LED HD Ready\r\nWi-Fi 802.11a/b/g/n/ac - Bluetooth 4.1 - Windows 10\r\nScheda grafica AMD Radeon R5 M430(2GB Dedicata)', 499.99, 1),
(
18, 'CANON EOS 1300D 18-55 IS', 'Fotocamera Reflex digitale - Sensore CMOS da 18 Megapixel\r\nLCD da 3" - Filmati Full HD - Slot SD/SDHC\r\nObiettivo 18-55 IS - Interfaccia USB - Peso: 485 g.\r\nGaranzia ufficiale Canon Italia', 379.99, 3),
(
19, 'KOENIC KSI 270 ', 'Ferro a vapore - Potenza max: 2.700 W\r\nCapacità serbatoio: 350 ml - Regolazione\r\nvapore - Funzione spray - Spegnimento\r\nautomatico - Piastra: Ceramica rivestita', 25.99, 5),
(
21, 'MT DISTRIBUTION TEKKDRONE VAMPIRE PLUS', 'Minidrone - Camera HD da 2 megapixel\r\nGiroscopio 6 assi\r\nLuci LED per utilizzo notturno\r\nAutonomia 14/16 minuti\r\nDistanza di controllo 100 metri\r\nFunzione hovering - headless mode\r\nTasto one key return ', 89.99, 7),
(
22, 'SAMSUNG UE55KU6000KXZT', 'SMART TV LED 55" Ultra HD 4K - Risoluzione: 3840x2160\r\nTecnologia 1300 PQI - DLNA - WiFi + Ethernet\r\nTuner Digitale Terrestre DVB-T2\r\nClasse efficienza energetica: A\r\nDistribuito da Samsung Italia', 699.99, 2),
(
23, 'SONY PS4 PRO 1TB ', 'Console fissa - 1000 GB HDD\r\nLettore BD/ DVD - Controller wireless\r\nBluetooth - HDMI - USB', 409.99, 6),
(
24, 'BEKO RDSA240K20W', 'Frigorifero Doppia porta\r\nClasse di efficienza energetica: A\r\nCapacità netta frigo: 177 l\r\nCapacità netta congelatore: 46 l\r\nConsumo energia annuo: 226 kWh/anno\r\nSistema di raffreddamento frigo: Statico\r\nColore: Bianco', 259.99, 4),
(
25, 'DE LONGHI EDG 100.W + 48 Capsule ', 'Macchina per caffè - Pressione: 15 bar - Potenza: 1460 W\r\nLeva di erogazione - Stand-by automatico - Sistema\r\nThermoblock - Cassettino raccogligocce regolabile in altezza\r\nFunzionamento esclusivo con cialde Nescafè Dolce Gusto', 49.99, 5);

-- --------------------------------------------------------

--
-- Table structure for table `ProductsShowrooms`
--

CREATE TABLE `ProductsShowrooms` (
 
`id_product` int(11) NOT NULL,
 
`id_showroom` int(11) NOT NULL
)
ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- RELATIONS FOR TABLE `ProductsShowrooms`:
--   `id_product`
--           `Products` -> `id`
--   `id_showroom`
--           `Showrooms` -> `id`
--

--
-- Dumping data for table `ProductsShowrooms`
--

INSERT INTO `ProductsShowrooms` (`id_product`, `id_showroom`) VALUES
(
1, 1),
(
5, 1),
(
6, 1),
(
7, 1),
(
9, 1),
(
1, 2),
(
2, 2),
(
6, 2),
(
7, 2),
(
9, 2),
(
1, 3),
(
2, 3),
(
3, 3),
(
7, 3),
(
9, 3),
(
2, 4),
(
3, 4),
(
4, 4),
(
8, 4),
(
3, 5),
(
4, 5),
(
5, 5),
(
8, 5),
(
4, 6),
(
5, 6),
(
6, 6),
(
8, 6);

-- --------------------------------------------------------

--
-- Table structure for table `Showrooms`
--

CREATE TABLE `Showrooms` (
 
`id` int(11) NOT NULL,
 
`name` varchar(50) NOT NULL,
 
`address` varchar(100) NOT NULL,
 
`city` varchar(50) NOT NULL,
 
`phone` varchar(12) DEFAULT NULL,
 
`site` varchar(50) DEFAULT NULL
)
ENGINE=InnoDB DEFAULT CHARSET=latin1;

--
-- RELATIONS FOR TABLE `Showrooms`:
--

--
-- Dumping data for table `Showrooms`
--

INSERT INTO `Showrooms` (`id`, `name`, `address`, `city`, `phone`, `site`) VALUES
(
1, 'show1', 'address1', 'city1', '123456781', 'http://www.show1.com'),
(
2, 'show2', 'address2', 'city2', '123456782', 'http://www.show2.com'),
(
3, 'show3', 'address3', 'city3', '123456783', 'http://www.show3.com'),
(
4, 'show4', 'address4', 'city4', '123456784', NULL),
(
5, 'show5', 'address5', 'city5', NULL, 'http://www.show5.com'),
(
6, 'show6', 'address6', 'city6', '123456786', 'http://www.show6.com');

--
-- Indexes for dumped tables
--

--
-- Indexes for table `Categories`
--
ALTER TABLE `Categories`
 
ADD PRIMARY KEY (`id`);

--
-- Indexes for table `Products`
--
ALTER TABLE `Products`
 
ADD PRIMARY KEY (`id`),
 
ADD KEY `id_category` (`id_category`);

--
-- Indexes for table `ProductsShowrooms`
--
ALTER TABLE `ProductsShowrooms`
 
ADD PRIMARY KEY (`id_product`,`id_showroom`),
 
ADD KEY `id_showroom` (`id_showroom`);

--
-- Indexes for table `Showrooms`
--
ALTER TABLE `Showrooms`
 
ADD PRIMARY KEY (`id`);

--
-- AUTO_INCREMENT for dumped tables
--

--
-- AUTO_INCREMENT for table `Categories`
--
ALTER TABLE `Categories`
 
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=10;
--
-- AUTO_INCREMENT for table `Products`
--
ALTER TABLE `Products`
 
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=26;
--
-- AUTO_INCREMENT for table `Showrooms`
--
ALTER TABLE `Showrooms`
 
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=7;
--
-- Constraints for dumped tables
--

--
-- Constraints for table `Products`
--
ALTER TABLE `Products`
 
ADD CONSTRAINT `Products_ibfk_1` FOREIGN KEY (`id_category`) REFERENCES `Categories` (`id`);

--
-- Constraints for table `ProductsShowrooms`
--
ALTER TABLE `ProductsShowrooms`
 
ADD CONSTRAINT `ProductsShowrooms_ibfk_1` FOREIGN KEY (`id_product`) REFERENCES `Products` (`id`),
 
ADD CONSTRAINT `ProductsShowrooms_ibfk_2` FOREIGN KEY (`id_showroom`) REFERENCES `Showrooms` (`id`);

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;


Server di connessione al database EsempioREST

Nel server per la gestione della connessione al database viene definita una interfaccia per specificare i metodi utilizzabili per la conversione dei dati del database in formato XML o JSON (quest’ultimo non è imlementato). I due metodi dichiarati saranno poi definiti nelle classi relative alle tre entità del database. Il server implementa diversi metodi per l’interrogazione del database EsempioREST.

L’intera implementazione del server di gestione del database viene inserita come libreria nel Web service che offre il servizio, il cui codice è mostrato nel seguito della trattazione.

Bointerface.java

package simple.bo;

public interface BoInterface {
 
public String toXml();
 
public String toJson();
}

Di seguito vengono definite le classi per manipolare i dati del database come oggetti.

Category.java

La classe Category sarà usata per creare oggetti derivanti dalla tabella Categories che contiene le diverse categorie dei prodotti.

package simple.bo;

public class Category implements BoInterface {

 
private int id = -1;
 
private String description;

 
public Category(int id, String description) {
   
this.id = id;
   
this.description = description;
 }

 
public Category(String description) {
   
this.description = description;
 }

 
public int getId() {
   
return id;
 }

 
public String getDescription() {
   
return description;
 }

 
public void setDescription(String description) {
   
this.description = description;
 }

 
@Override
 
public int hashCode() {
   
int hash = 7;
   hash =
59 * hash + this.id;
   
return hash;
 }

 
@Override
 
public boolean equals(Object obj) {
   
if (obj == null) {
       
return false;
   }
   
if (getClass() != obj.getClass()) {
       
return false;
   }
   
final Category other = (Category) obj;
   
if (this.id != other.id) {
       
return false;
   }
   
return true;
 }

  // Restituisce un elemento XML
 
public String toXml() {
   
return "<category id=\"" + id + "\"><description>" + description
          +
"</description></category>";
 }

  // Restituisce un elemento Json
 
public String toJson() {
   
return "{\n\"category\"\n{\n\"id\":\"" + id + "\",\n\"description\":\""
           + description +
"\"\n}\n}";
 }
}


Product.java

La classe Product sarà usata per creare oggetti derivanti dalla tabella Products che contiene tutti i prodotti gestiti, ognuno appartenente ad una specifica categoria.

package simple.bo;

public class Product implements BoInterface {

 
private int id = -1;
 
private String name;
 
private String description = null;
 
private float price;
 
private Category category;

  // Costruttore di un prodotto.

  // L’attributo che conterrà la categoria è un riferimento all’oggetto che

  // identifica la categoria stessa, non un identificatore, come avviene nel db.

  // La rappresentazione dei dati usando un linguaggio ad oggetti, non

  // necessariamente deve essere riprodotta esattamente. In questo caso è stato

  // scelto di memorizzare direttamente il riferimento alla categoria invece di

  // salvarne il codice.
 
public Product(int id, String name, String description, float price, Category category) {
   
this.id = id;
   
this.name = name;
   
this.price = price;
   
this.description=description;
   
this.category = category;
 }

 
public Product(String name, String description, float price, Category category) {
   
this.name = name;
   
this.description = description;
   
this.price = price;
   
this.category = category;
 }

 
public int getId() {
   
return id;
 }

 
public String getName() {
   
return name;
 }

 
public String getDescription() {
   
return description;
 }

 
public float getPrice() {
   
return price;
 }

 
public Category getCategory() {
   
return category;
 }

 
public void setDescription(String description) {
   
this.description = description;
 }

 
public void setPrice(float price) {
   
this.price = price;
 }

 
public void setCategory(Category category) {
   
this.category = category;
 }

 
@Override
 
public int hashCode() {
   
int hash = 7;
   hash =
71 * hash + this.id;
   
return hash;
 }

 
@Override
 
public boolean equals(Object obj) {
   
if (obj == null) {
       
return false;
   }
   
if (getClass() != obj.getClass()) {
       
return false;
   }
   
final Product other = (Product) obj;
   
if (this.id != other.id) {
       
return false;
   }
   
return true;
 }

  // Restituisce un elemento XML
 
public String toXml() {
   String s =
"<product id=\"" + id + "\"><name>" + name + "</name>";
   s +=
"<description>" + description + "</description>";
   s +=
"<price>" + price + "</price>";
   s += category.toXml() +
"</product>";
   
return s;
 }
 

  // Restituisce un elemento Json
 
public String toJson() {
   String s =
"{\n\"product\"\n{\n\"id\":\"" + id + "\",\n";
   s +=
"\"name\":\"" + name + "\",\n";
   s +=
"\"description\":\"" + description + "\",\n";
   s +=
"\"price\":\"" + price + "\",\n";
   s += category.toJson();
   s +=
"\n}\n}";
   
return s;
 }
}


Showroom.java

La classe Showroom sarà usata per creare oggetti derivanti dalla tabella Showrooms che contiene tutti i negozi della catena.

package simple.bo;

public class Showroom implements BoInterface {

 
private int id = -1;
 
private String name;
 
private String address;
 
private String city;
 
private String phone;
 
private String site;

 
public Showroom(int id, String name, String address, String city) {
   
this.id = id;
   
this.name = name;
   
this.address = address;
   
this.city = city;
 }

 
public Showroom(String name, String address, String city, String phone, String site) {
   
this.name = name;
   
this.address = address;
   
this.city = city;
   
this.phone = phone;
   
this.site = site;
 }

 
public int getId() {
   
return id;
 }

 
public String getName() {
   
return name;
 }

 
public String getAddress() {
   
return address;
 }

 
public String getCity() {
   
return city;
 }

 
public String getPhone() {
   
return phone;
 }

 
public String getSite() {
   
return site;
 }

 
public void setPhone(String phone) {
   
this.phone = phone;
 }

 
public void setSite(String site) {
   
this.site = site;
 }

 
@Override
 
public int hashCode() {
   
int hash = 3;
   hash =
79 * hash + this.id;
   
return hash;
 }

 
@Override
 
public boolean equals(Object obj) {
   
if (obj == null) {
       
return false;
   }
   
if (getClass() != obj.getClass()) {
       
return false;
   }
   
final Showroom other = (Showroom) obj;
   
if (this.id != other.id) {
       
return false;
   }
   
return true;
 }

  // Restituisce un elemento Json
 
public String toXml() {
   String s =
"<showroom id=\"" + id + "\"><name>" + name + "</name>";
   s +=
"<address>" + address + "</address><city>" + city + "</city>";
   
if (phone != null) {
       s +=
"<phone>" + phone + "</phone>";
   }
   
if (site != null) {
       s +=
"<site>" + site + "</site>";
   }
   s +=
"</showroom>";
   
return s;
 }

  // Restituisce un elemento Json
 
@Override
 
public String toJson() {
   
throw new UnsupportedOperationException("Not supported yet.");

  }
}


Server.java (finire di commentare)

Nel server mancano le interrogazioni al database:

  • prodotto per categoria;
  • negozi che vendono un prodotto;
  • tutti i prodotti venduti da un negozio.

Provare ad implementarli come esercizio.

package simple.db;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import simple.bo.Category;
import simple.bo.Product;
import simple.bo.Showroom;

/**
*
*
@author palma

 * Mancano le interrogazioni al database di:

 * - Prodotto per Categoria

 * - Negozi che vendono un prodotto

 * - Tutti i prodotti venduti da un negozio
*/

public class Server {
   
// La classe Connection permette di connettersi ad un database.
   Connection connection;
   
// La classe Statement permette di eseguire una query al database.
   Statement statement;
   
// La classe ResultSet contiene il risultato della query effettuata sul
   
// database.
   ResultSet resultSet;

   
/**
    * Il costruttore prende come parametro formale la stringa di connessione
    * al database.
    */

   
public Server(String connectionString) {
       
try {
           
// La classe DriverManager è il servizio di base per la gestione
           
// dei driver JDBC, mentre il metodo getConnection() permette di
           
// creare una connessione al database identificato dalla stringa
           
// fornita come parametro attuale.
           connection = DriverManager.getConnection(connectionString);
           
// Il metodo createStatement() crea un oggetto Statement utilizzato
           
// per inviare istruzioni SQL al database.
           statement = connection.createStatement();
       }
catch (SQLException ex) {
           
throw new RuntimeException("Impossibile connettersi al database");
       }
   }

   
/**
    * Il metodo memorizza in un ArrayList l'elenco di tutte le categorie
    * presenti nella tabella Categories.
    *
@return elenco di oggetti Category
    */

   
public List<Category> selectCategories() {
       List<Category> list =
new ArrayList();
       
try {
           
// Il metodo executeQuery() dell'interfaccia Statement esegue una
           
// istruzione SQL fornita come parametro attuale, e restituisce un
           
// singolo oggetto ResultSet.
           resultSet = statement.executeQuery(
"select * from Categories");
           
while (resultSet.next()) {
               
// I metodi getInt() e getString() dell'interfaccia ResultSet
               
// recuperano il valore nella colonna passata come parametro
               
// attuale ai metodi, dell'attuale riga dell'oggetto ResultSet.
               
// Il metodo getInt() trasforma il valore in un intero, mentre
               
// il metodo getString() lo trasforma in una stringa.
               
// Il parametro passato nei metodi può essere un numero o una
               
// stringa. Il primo identifica la posizione della colonna, il
               
// secondo l'attributo della tabella nel database.
               list.add((Category) (
new Category(resultSet.getInt(1),
                       resultSet.getString(
2))));
           }
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return list;
   }

   
/**
    * Il metodo memorizza in un ArrayList l'elenco di tutti i negozi
    * presenti nella tabella Showrooms.
    *
@return elenco di oggetti Showroom
    */

   
public List<Showroom> selectShowrooms() {
       List<Showroom> list =
new ArrayList();
       Showroom ss =
null;
       
try {
           resultSet = statement.executeQuery(
"select * from Showrooms");
           
while (resultSet.next()) {
               ss =
new Showroom(resultSet.getInt(1), resultSet.getString(2),
                       resultSet.getString(
3), resultSet.getString(4));
               ss.setPhone(resultSet.getString(
5));
               ss.setSite(resultSet.getString(
6));
               list.add((Showroom) ss);

           }
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return list;
   }

   
/**
    * Il metodo memorizza in un ArrayList l'elenco di tutti i prodotti
    * presenti nella tabella Products, ognuno associato alla relativa
    * categoria.
    *
@return elenco di oggetti Product
    */

   
public List<Product> selectProducts() {
       List<Product> list =
new ArrayList();
       Category sc =
null;
       Product sp =
null;
       
try {
           resultSet = statement.executeQuery(
"select * from Products, "
                   +
"Categories where id_category=Categories.id");
           
while (resultSet.next()) {
               
if (sc == null || sc.getId() != resultSet.getInt(6)) {
                   sc =
new Category(resultSet.getInt(6), resultSet.getString(7));
               }
               sp =
new Product(resultSet.getInt(1), resultSet.getString(2),
                       resultSet.getString(
3),resultSet.getFloat(4), (Category) sc);
               list.add((Product) sp);

           }
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return list;
   }

   
/**
    * Il metodo seleziona dal database l'istanza di Categories identificata
    * dalla chiave primaria passata come parametro al metodo.
    *
@param id chiave primaria che identifica l'istanza nella tabella
    * Categories.
    *
@return l'oggetto Category con i dati estratti dal database.
    */

   
public Category selectCategory(int id) {
       Category c =
null;
       
try {
           resultSet = statement.executeQuery(
"select * from Categories where id=" + id);
           
if (resultSet.next()) {
               c = (Category) (
new Category(resultSet.getInt(1), resultSet.getString(2)));
           }
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return c;
   }

   
/**
    * Il metodo seleziona dal database l'istanza di Showroom identificata
    * dalla chiave primaria passata come parametro al metodo.
    *
@param id chiave primaria che identifica l'istanza nella tabella
    * Showrooms.
    *
@return l'oggetto Showroom con i dati estratti dal database.
    */

   
public Showroom selectShowroom(int id) {
       Showroom ss =
null;
       
try {
           resultSet = statement.executeQuery(
"select * from Showrooms where id=" + id);
           
if (resultSet.next()) {
               ss =
new Showroom(resultSet.getInt(1), resultSet.getString(2),
                       resultSet.getString(
3), resultSet.getString(4));
               ss.setPhone(resultSet.getString(
5));
               ss.setSite(resultSet.getString(
6));
           }
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return (Showroom) ss;
   }

   
/**
    * Il metodo seleziona dal database l'istanza di Products identificata
    * dalla chiave primaria passata come parametro al metodo.
    *
@param id chiave primaria che identifica l'istanza nella tabella
    * Products.
    *
@return l'oggetto Product con i dati estratti dal database.
    */

   
public Product selectProduct(int id) {
       Category sc =
null;
       Product sp =
null;
       
try {
           resultSet = statement.executeQuery(
"select * from Products, Categories "
                   +
"where id_category=Categories.id and Products.id=" + id);
           
if (resultSet.next()) {
               sc =
new Category(resultSet.getInt(6), resultSet.getString(7));
               sp =
new Product(resultSet.getInt(1), resultSet.getString(2),
                       resultSet.getString(
3),resultSet.getFloat(4), (Category) sc);
           }
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return (Product) sp;
   }
   
 
public int deleteProduct(Product p){
       
return deleteProduct(p.getId());
   }
   
   
public int deleteProduct(int id) {
       
int n = 0;
       
try {
           n = statement.executeUpdate(
"delete from Products where id=" + id);
           statement.executeUpdate(
"delete from ProductsShowrooms where id_product=" + id);
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return n;
   }

   
public int deleteShowroom(Showroom s){
       
return deleteShowroom(s.getId());
   }
   
   
public int deleteShowroom(int id) {
       
int n = 0;
       
try {
           n = statement.executeUpdate(
"delet from Showroom where id=" + id);
           statement.executeUpdate(
"delete from ProductsShowrooms where id_showroom=" + id);
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return n;
   }

   
public int deleteCategory(Category c){
       
return deleteCategory(c.getId());
   }
   
   
public int deleteCategory(int id) {
       
int n = 0;
       
try {
           statement.executeUpdate(
"delete from Products " 
                   +
" where id_category=" + id);
            n = statement.executeUpdate(
"delete from Categories where id=" + id);
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
       
return n;
   }

   
public int updateCategory(Category c) {
       
try {
           
return statement.executeUpdate("update Categories set description='"
                   + c.getDescription() +
"' where id=" + c.getId());
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
   }

   
public int updateShowroom(Showroom s) {
       
try {
           
return statement.executeUpdate("update Showrooms set phone='"
                   + s.getPhone() +
"', site='" + s.getSite() + "' where id=" + s.getId());
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
   }

   
public int updateProduct(Product p) {
       
try {
           
return statement.executeUpdate("update Products set description='"
                   + p.getDescription() +
"', price=" + p.getPrice() + ", id_category="
                   + p.getCategory().getId() +
" where id=" + p.getId());
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
   }

   
public int insertProduct(Product p) {
       
try {
           
return statement.executeUpdate("insert into Products (name,description"
                   +
",price,id_category) values ('" + p.getName() + "','" + p.getDescription()
                   +
"'," + p.getPrice() + "," + p.getCategory().getId() + ")");
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
   }

   
public int insertShowroom(Showroom s) {
       
try {
           
return statement.executeUpdate("insert into Showrooms (name,address"
                   +
",city,phone,site) values ('" + s.getName() + "','" + s.getAddress()
                   +
"','" + s.getCity() + "','" + s.getPhone() + "','" + s.getSite() + "')");
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
   }

   
public int insertCategory(Category c) {
       
try {
           
return statement.executeUpdate("insert into Categories (description)"
                   +
" values ('" + c.getDescription() + "')");
       }
catch (SQLException ex) {
           
throw new RuntimeException("Errore nell'esecuzione della query");
       }
   }
}


Web service REST SimpleRestDb

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" 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/web-app_3_1.xsd"
>
   
<servlet>
       
<servlet-name>Crud</servlet-name>
       
<servlet-class>simplerestdb.Crud</servlet-class>
       
<init-param>
           
<param-name>connectionString</param-name>
           
<param-value>
       jdbc:mysql://localhost:3306/EsempioRest?user=root&amp;password=password
           
</param-value>
       
</init-param>
   
</servlet>
   
<servlet-mapping>
       
<servlet-name>Crud</servlet-name>
       
<url-pattern>/*</url-pattern>
   
</servlet-mapping>
   
<session-config>
       
<session-timeout>
           30
       
</session-timeout>
   
</session-config>
</web-app>

Crud.java

package simplerestdb;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import parser.CategoryParser;
import parser.ProductParser;
import simple.bo.Category;
import simple.bo.Product;
import simple.bo.Showroom;
import simple.db.Server;

/**
*
*
@author palma

 * Manca il parser degli Showroom, implementatelo per esercizio.
*/

public class Crud extends HttpServlet {

   
/**
    * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
    * methods.
    *
    *
@param request servlet request
    *
@param response servlet response
    *
@throws ServletException if a servlet-specific error occurs
    *
@throws IOException if an I/O error occurs
    */

   
   
private Server server;

   
/**
    * Handles the HTTP <code>GET</code> method.
    *
    *
@param request servlet request
    *
@param response servlet response
    *
@throws ServletException if a servlet-specific error occurs
    *
@throws IOException if an I/O error occurs
    */

   
@Override
   
protected void doGet(HttpServletRequest request, HttpServletResponse response)
           
throws ServletException, IOException {
       PrintWriter out = response.getWriter();
       response.setContentType(
"application/xml;charset=UTF-8");
       String[] parts = request.getRequestURI().split(
"/");
       
if (parts != null && (parts.length == 4 || parts.length == 3 
               || parts.length ==
2)) {
           
if (parts.length == 4) {
               selectOne(parts, out, response);
           }
else {
               
if (parts.length == 3) {
                   selectAll(parts, out, response);
               }
else {
                   istructions(out);
               }
           }
       }
else {
           response.sendError(
400);
       }
   }

   
@Override
   
protected void doPost(HttpServletRequest request,
           HttpServletResponse response)

           
throws ServletException, IOException {
       insertOrUpdate(request, response,
1);
   }

   
@Override
   
protected void doPut(HttpServletRequest request,
           HttpServletResponse response)

           
throws ServletException, IOException {
       insertOrUpdate(request, response,
2);
   }

   
@Override
   
protected void doDelete(HttpServletRequest request,
           HttpServletResponse response)

           
throws ServletException, IOException {
       String[] parts = request.getRequestURI().split(
"/");
       
if (parts != null && parts.length == 4) {
           String typeOfObject = parts[
2];
           String idObject = parts[
3];
           
if (idObject != null) {
               
int n = -1;
               
try {
                   PrintWriter out = response.getWriter();
                   
switch (typeOfObject) {
                       
case "product":
                           n = server.deleteProduct(Integer.parseInt(idObject));
                           
break;
                       
case "category":
                           n = server.deleteCategory(Integer.parseInt(idObject));
                           
break;
                       
case "showroom":
                           n = server.deleteShowroom(Integer.parseInt(idObject));
                           
break;
                   }
                   out.println(
"<result status=\"200\">" + n
                           +
" record</result>");
               }
catch (IllegalArgumentException ex) {
                   response.sendError(
400);
               }
           }
else {
               response.sendError(
400);
           }
       }
else {
           response.sendError(
400);
       }
   }

   
private void selectAll(String[] parts, PrintWriter out,
           HttpServletResponse response)
 
           
throws IOException, IllegalArgumentException {
       String typeOfObject = parts[
2];
       
switch (typeOfObject) {
           
case "products":
               List<Product> products = server.selectProducts();
               out.println(
"<result status=\"200\">");
               out.println(
"<" + typeOfObject + ">");
               
for (Product product : products) {
                   out.println(product.toXml());
               }
               out.println(
"</"+ typeOfObject + ">");
               out.println(
"</result>");
               
break;
           
case "categories":
               out.println(
"<result status=\"200\">");
               out.println(
"<" + typeOfObject + ">");
               List<Category> categories = server.selectCategories();
               
for (Category product : categories) {
                   out.println(product.toXml());
               }
               out.println(
"</"+ typeOfObject + ">");
               out.println(
"</result>");
               
break;
           
case "showrooms":
               out.println(
"<result status=\"200\">");
               out.println(
"<" + typeOfObject + ">");
               List<Showroom> showrooms = server.selectShowrooms();
               
for (Showroom showroom : showrooms) {
                   out.println(showroom.toXml());
               }
               out.println(
"</"+ typeOfObject + ">");
               out.println(
"</result>");
               
break;
           
default:response.sendError(400);
       }
   }

   
private void selectOne(String[] parts, PrintWriter out,
           HttpServletResponse response)
 throws IOException {
       String typeOfObject = parts[
2];
       String idObject = parts[
3];
       
if (idObject != null) {
           
try {
               
switch (typeOfObject) {
                   
case "product":
                       Product product = server.selectProduct(Integer.parseInt(idObject));
                       
if (product != null) {
                           out.println(
"<result status=\"200\">");
                           out.println(product.toXml());
                           out.println(
"</result>");
                       }
else{
                           out.println(
"<result status=\"200\"/>");
                       }
                       
break;
                   
case "category":
                       Category category = server.selectCategory(Integer.parseInt(idObject));
                       
if (category != null) {
                           out.println(
"<result status=\"200\">");
                           out.println(category.toXml());
                           out.println(
"</result>");
                       }
else{
                           out.println(
"<result status=\"200\"/>");
                       }
                       
break;
                   
case "showroom":
                       Showroom showroom = server.selectShowroom(Integer.parseInt(idObject));
                       
if (showroom != null) {
                           out.println(
"<result status=\"200\">");
                           out.println(showroom.toXml());
                           out.println(
"</result>");
                       }
else{
                           out.println(
"<result status=\"200\"/>");
                       }
                       
break;
                   
default:response.sendError(400);
               }
           }
catch (IllegalArgumentException ex) {
               response.sendError(
400);
           }
       }
else {
           response.sendError(
400);
       }
   }

   
private void insertOrUpdate(HttpServletRequest request,
           HttpServletResponse response,
int index) throws IOException {
       String url = request.getRequestURI();
       String[] parts = url.split(
"/");
       
if (parts != null && parts.length == 3) {
           String typeOfObject = parts[
2];
           
try {
               String input =
"";
               BufferedReader br =
new BufferedReader(request.getReader());
               String line;
               
while ((line = br.readLine()) != null) {
                   input += line;
               }
               
if (!input.isEmpty()) {
                   
int n = -1;
                   
switch (typeOfObject) {
                       
case "product":
                           ProductParser productParser =
new ProductParser(input, true);
                           Product product = productParser.parse();
                           
if (index == 1) {
                               n = server.insertProduct(product);
                           }
else {
                               n = server.updateProduct(product);
                           }
                           
break;
                       
case "category":
                           CategoryParser categoryParser =
new CategoryParser(input, true);
                           Category category = categoryParser.parse();
                           
if (index == 1) {
                               n = server.insertCategory(category);
                           }
else {
                               n = server.updateCategory(category);
                           }
                           
break;
                       
case "showroom":
                           
//da fare
                           
break;
                   }
                   PrintWriter out = response.getWriter();
                   response.setContentType(
"application/xml;charset=UTF-8");
                   out.println(
"<result status=\"200\">" + n + " record</result>");
               }
else {
                   response.sendError(
400);
               }
           }
catch (Exception ex) {
               response.sendError(
500, ex.getLocalizedMessage());
           }
       }
else {
           response.sendError(
400);
       }
   }

   
@Override
   
public void init() {
       
try {
           Class.forName(
"com.mysql.jdbc.Driver");
           server =
new Server(getInitParameter("connectionString"));
       }
catch (ClassNotFoundException ex) {
           
throw new RuntimeException(ex);
       }
   }

   
/**
    * Returns a short description of the servlet.
    *
    *
@return a String containing servlet description
    */

   
@Override
   
public String getServletInfo() {
       
return "Short description";
   }

   
private void istructions(PrintWriter out) {
       out.println(
"<SelectObjects>");
       out.println(
"<product>");
       out.println(
"<one>applicationaddress/product/id</one>");
       out.println(
"<all>ApplicationAddress/products</all>");
       out.println(
"</product>");
       out.println(
"<product>");
       out.println(
"<one>applicationaddress/showroom/id</one>");
       out.println(
"<all>ApplicationAddress/showrooms</all>");
       out.println(
"</product>");
       out.println(
"<product>");
       out.println(
"<one>ApplicationAddress/category/id</one>");
       out.println(
"<all>ApplicationAddress/categories</all>");
       out.println(
"</product>");
       out.println(
"</SelectObjects>");
   }
}

CategoryParser.java (commentare)

package parser;

import java.io.ByteArrayInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import simple.bo.Category;

/**
*
*
@author palma
*/

public class CategoryParser  {

   
private final boolean xml;
   
private final String s;
   
private  Element root = null;
   
   
public CategoryParser(String s, boolean xml) throws Exception {
       
this.xml = xml;
       
this.s = s;
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
       DocumentBuilder builder = factory.newDocumentBuilder();
       Document document = builder.parse(
new ByteArrayInputStream(s.getBytes()));
       root = document.getDocumentElement();
   }

   
public Category parse() throws Exception {
       Category parsed =
null;
       
if (xml) {
           parsed = parseXml();
       }
else {
           parsed = parseJson();
       }
       
return parsed;
   }

   
private Category parseXml() throws Exception {
       Category c =
null;
       
int id = -1;
       NodeList list = root.getElementsByTagName(
"category");
       
if (list != null && list.getLength() > 0) {
           String description = list.item(
0).getFirstChild().getFirstChild().getNodeValue();
           
if (description != null && !description.isEmpty()) {
               Node nId = list.item(
0).getAttributes().getNamedItem("id");
               String sid =
null;
               
if (nId != null) {
                   sid = nId.getNodeValue();
                   
try {
                       id = Integer.parseInt(sid);
                   }
catch (NumberFormatException ex) {
                       
throw new Exception(ex);
                   }
                   c =
new Category(id, description);
               }
else {
                   c =
new Category(description);
               }
           }
else {
               
throw new Exception("XMl error: incorrect description ");
           }
       }
else {
           
if (root.getNodeName().equals("category")) {
               list = root.getElementsByTagName(
"description");
               
if (list != null && list.getLength() > 0) {
                   String description = list.item(
0).getFirstChild().getNodeValue();
                   String sid = root.getAttribute(
"id");
                   
if (sid != null && !sid.isEmpty()) {
                       
try {
                           id = Integer.parseInt(sid);
                       }
catch (NumberFormatException ex) {
                           
throw new Exception(ex);
                       }
                       c =
new Category(id, description);
                   }
else {
                       c =
new Category(description);
                   }
               }
else {
                   
throw new Exception("XML error: no description");
               }
           }
else {
               
throw new Exception("XML error: no category");
           }

       }
       
return c;
   }

   
private Category parseJson() {
       
throw new UnsupportedOperationException("Not supported yet.");
   }
}

ProductParser.java (commentare)

package parser;

import java.io.ByteArrayInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import simple.bo.Category;
import simple.bo.Product;

/**
*
*
@author palma
*/

public class ProductParser {

   
private final boolean xml;
   
private final String s;
   
private Element root = null;

   
public ProductParser(String s, boolean xml) throws Exception {
       
this.xml = xml;
       
this.s = s;
       DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
       DocumentBuilder builder = factory.newDocumentBuilder();
       Document document = builder.parse(
new ByteArrayInputStream(s.getBytes()));
       root = document.getDocumentElement();
   }

   
public Product parse() throws Exception {
       Product parsed =
null;
       
if (xml) {
           parsed = parseXml();
       }
else {
           parsed = parseJson();
       }
       
return parsed;
   }

   
private Product parseXml() throws Exception {
       Product p =
null;
       String name =
null;
       String description =
null;
       
float price = 0;
       
int id = -1;

       NodeList list = root.getElementsByTagName(
"name");
       
if (list != null && list.getLength() > 0) {
           name = list.item(
0).getFirstChild().getNodeValue().trim();
           list = root.getElementsByTagName(
"description");
           
if (list != null && list.getLength() > 0) {
               description = list.item(
0).getFirstChild().getNodeValue().trim();
           }
           list = root.getElementsByTagName(
"price");
           
if (list != null && list.getLength() > 0) {
               price = Float.parseFloat(list.item(
0).getFirstChild().getNodeValue().trim());
               CategoryParser parser =
new CategoryParser(s, true);
               Category category = (Category) parser.parse();
               String sid = root.getAttribute(
"id");
               
if (sid != null && !sid.isEmpty()) {
                   id = Integer.parseInt(sid);
                   p =
new Product(id, name, description, price, category);
               }
else {
                   p =
new Product(name, description, price, category);
               }
               
return p;
           }
else {
               
throw new Exception("L'XML error: incorrect price");
           }
       }
else {
           
throw new Exception("XML error: incorrect name");
       }
   }

   
private Product parseJson() {
       
throw new UnsupportedOperationException("Not supported yet.");
   }
}

ShowroomParser.java

Manca, da implementare per esercizio.

Client RestClient

RestClient.java

package restclient;

import java.awt.HeadlessException;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.JOptionPane;

/**
*
*
@author palma
*/

public class RestClient {

   
/**
    *
@param args the command line arguments
    */

   
public static void main(String[] args) {
       
//Per lavorare sulle tre tabella
       String product=
"product";
       String showroom=
"showroom";
       String category=
"category";
       
       
//modifica  ha l'id
       String modifyProduct=
"<product id=\"20\"><name>xxxxx</name><description>"
               +
"cambio description</description><price>23.45</price>"
                   +
"<category id=\"3\"><description>qqqqqq</description>"
                   +
"</category></product>";
       String modifyShowroom=
"<showroom id=\"4\"><name>cambiato</name><address>address 8"
               +
"</address><city>umpapa</city><phone>12345</phone><site>"
               +
"www.puntopunto.it</site></showroom>";
       String modifyCategory=
"<category id=\"2\"><description>modifica</description>"
               +
"</category>";
       
//insert non ha id che viene messo dal db
       String insertProduct=
"<product><name>nuovo prodottoo</name><description>cambio"
               +
" description</description><price>23.45</price>"
                   +
"<category id=\"3\"><description>qqqqqq</description>"
                   +
"</category></product>";
       String insertShowroom=
"<showroom><name>show8</name><address>address 8"
               +
"</address><city>umpapa</city><phone>12345</phone><site>"
               +
"www.puntopunto.it</site></showroom>";
       String insertCategory=
"<category><description>nuova</description>"
               +
"</category>";
       
       insertOrModify(category, modifyCategory);
       
//id dell'oggetto da cancellare
       
//verificare sul db gli id presenti
       
//delete(category, "3");
   }

   
private static void insertOrModify(String table,String object) throws HeadlessException {
       
try{
           URL url =
new URL("http://localhost:8080/SimpleRestDb/"+table);
           HttpURLConnection conn = (HttpURLConnection) url.openConnection();
           conn.setRequestProperty(
"Accept", "application/xml");
           
//conn.setRequestMethod("POST");
           conn.setRequestMethod(
"PUT");
           conn.setDoOutput(
true);
           conn.setRequestProperty(
"Content-Type", "text/xml");
           conn.setRequestProperty(
"Connection", "Keep-Alive");
           conn.setRequestProperty(
"charset", "utf-8");
           PrintWriter out =
new PrintWriter(conn.getOutputStream());
           out.println(object);
           out.flush();
           out.close();
           BufferedReader br =
new BufferedReader(new InputStreamReader(
                   (conn.getInputStream())));
           String output;
           String s =
"";
           
while ((output = br.readLine()) != null) {
               s += output;
           }
           System.out.println(s);
           conn.disconnect();

       }
catch (MalformedURLException ex) {
           JOptionPane.showMessageDialog(
null, "Malformed url");
       }
catch (IOException ex) {
           JOptionPane.showMessageDialog(
null, "Connection problem");
       }
   }

   
private static void delete(String object,String id) {
       
try{
           URL url =
new URL("http://localhost:8080/RestDb/"+object+"/"+id);
           HttpURLConnection conn = (HttpURLConnection) url.openConnection();
           conn.setRequestProperty(
"Accept", "application/xml");
           conn.setRequestMethod(
"DELETE");
           conn.setRequestProperty(
"Content-Type", "text/xml");
           conn.setRequestProperty(
"Connection", "Keep-Alive");
           conn.setRequestProperty(
"charset", "utf-8");
           BufferedReader br =
new BufferedReader(new InputStreamReader(
                   (conn.getInputStream())));
           String output;
           String s =
"";
           
while ((output = br.readLine()) != null) {
               s += output;
           }
           System.out.println(s);
           conn.disconnect();

       }
catch (MalformedURLException ex) {
           JOptionPane.showMessageDialog(
null, "Malformed url");
       }
catch (IOException ex) {
           JOptionPane.showMessageDialog(
null, "Connection problem");
       }
   }
}


Esercizi

Esercizi sui protocolli di comunicazione

Socket TCP

  1. Progettare un protocollo comunicativo che permetta di interrogare un server per ottenere la data e l’ora del server stesso. La comunicazione deve avvenire utilizzando il protocollo TCP a livello di trasporto. Del protocollo comunicativo si dovranno definire:
  1. la tipologia di protocollo (controllo connessione: connection-oriented o connectionless);
  2. la porta di ascolto del server (indirizzamento);
  3. se i dati devono essere frammentati prima della spedizione o meno (frammentazione e riassemblaggio);
  4. i comandi utilizzati per la richiesta e la risposta;
  5. il formato dei messaggi di richiesta e di risposta;
  6. la semantica dei campi di ogni messaggio.

Si prevedano anche opportuni messaggi di errore inviati dal server.
Si facciano tutte le ipotesi aggiuntive ritenute necessarie, purché giustificate.

  1. Il sistema informatico del magazzino di un grande sito web di e-commerce mantiene per ogni prodotto in vendita, identificato da un codice numerico, la quantità disponibile.
    Progettare un protocollo di comunicazione tra client e server, basata su TCP, che debba prevedere le seguenti operazioni:
  1. a richiesta del client il server deve restituire la quantità presente in magazzino di un prodotto, specificato nell’interrogazione del client;
  2. il server modifichi la quantità di un prodotto specificato nel comando inviato dal client.

Del protocollo comunicativo si dovranno definire:

  1. la tipologia di protocollo (connection-oriented o connectionless);
  2. la porta di ascolto del server;
  3. i comandi utilizzati per la richiesta e la risposta;
  4. il formato dei messaggi di richiesta e di risposta;
  5. la semantica dei campi di ogni messaggio.

Si prevedano anche opportuni messaggi di errore inviati dal server.

Si facciano tutte le ipotesi aggiuntive ritenute necessarie, purché giustificate.

  1. Un piccolo cinema dispone di 3 sale con 100 posti ciascuna ed è necessario realizzare il servizio di prenotazione dei posti per i giorni festivi in cui in ciascuna delle sale sono proiettati 3 film, rispettivamente alle ore 17:30 (I spettacolo), alle ore 20:00 (II spettacolo) ed alle ore 22:30 (III spettacolo). Il servizio da realizzare consiste in un server TCP concorrente che risponde sulla porta 12345 alle seguenti richieste da parte dei client:
  1. elenco dei posti liberi per uno spettacolo in una certa sala;
  2. prenotazione di un elenco di posti liberi per uno spettacolo in una certa sala e per un certo spettacolo. Per questo caso il server dovrà restituire due  tipologie di messaggi diversi in caso di successo o insuccesso.

Del protocollo comunicativo si dovranno definire:

  1. la tipologia di protocollo (connection-oriented o connectionless);
  2. la porta di ascolto del server;
  3. i comandi utilizzati per la richiesta e la risposta;
  4. il formato dei messaggi di richiesta e di risposta;
  5. la semantica dei campi di ogni messaggio.

Si prevedano anche opportuni messaggi di errore inviati dal server.

Progettare il protocollo di comunicazione giustificando opportunamente tutte le ipotesi aggiuntive.

  1. Descrizione della realtà
    Un corriere espresso ha molti centri di accettazione e smistamento distribuiti sul territorio nazionale identificati dal codice di avviamento postale del luogo in cui si trovano.
    I
    pacchi che provvede ad accettare e smistare sul territorio sono identificati da un codice numerico generato al momento dell’accettazione.
    Il server memorizza in un file CSV l’elenco dei pacchi da consegnare con la lista dei centri in cui è transitato e i relativi
    timestamp in modo tale da ricostruire lo stato in cui si trova in caso di riavvio.
    Protocollo da implementare
    Un server TCP tiene traccia del centro accettazione e dei centri di smistamento in cui è transitato ogni singolo pacco con associata la data e l’ora di accettazione o transito (timestamp). Quando il server è attivo è in grado di accettare i seguenti comandi:
  1. accettazione di un nuovo pacco: il server genera il codice numerico da restituire al client, e dovrà registrare il centro di accettazione e il timestamp di accettazione che dovranno essergli forniti dal centro accettazione;
  2. transito del pacco da un centro di smistamento;
  3. richiesta dell’elenco del centro di accettazione e dei centri di smistamento con relativi timestamp da cui è transitato un determinato pacco; nella risposta deve essere fornito lo stato del pacco: già consegnato o non ancora consegnato;
  4. consegna del pacco al destinatario finale con registrazione del timestamp.

Del protocollo comunicativo si dovranno definire:

  1. la tipologia di protocollo (connection-oriented o connectionless);
  2. la porta di ascolto del server;
  3. i comandi utilizzati per la richiesta e la risposta;
  4. il formato dei messaggi di richiesta e di risposta;
  5. la semantica dei campi di ogni messaggio.

Si prevedano anche opportuni messaggi di errore inviati dal server.

Le eventuali ipotesi aggiuntive dovranno essere opportunamente giustificate.

Prova del protocollo comunicativo
Si ipotizzi uno schema di sequenza temporale (se si conosce si può usare un sequence diagram UML) per verificare se la sequenza di comandi progettata funziona logicamente. A tale scopo si prevedano due entità, l’insieme dei centri di accettazione e smistamento e il server, che si scambiano i messaggi.
Si partirà con il
centro di accettazione che invierà al server l’avvenuta accettazione di un nuovo pacco, seguito poi da tutti i centri di smistamento fino alla consegna finale. Ogni comando inviato da uno dei centri dovrà essere seguito dalla eventuale risposta del server.
La sequenza dovrà prevedere almeno una richiesta dell’elenco dei centri di accettazione/smistamento attraversati da parte di uno dei c
entri di accettazione/smistamento.

Socket UDP

  1. Un circolo nautico utilizza un dispositivo per interfacciare un sensore in grado di misurare velocità (Km/h) e direzione (°) del vento. Il produttore del sensore rende disponibile un driver che permette di acquisire i valori misurati ogni 5 secondi, in modo tale da permettere la memorizzazione dei dati per poi poterli usare in base alle necessità dell’utilizzatore del sensore.
    Una società che offre, fra le altre cose, informazioni metereologiche, intende realizzare un
    server UDP attivo sulla porta 54321 per rendere disponibili in rete i valori misurati dal sensore.
    Il
    server dovrà fornire le informazioni sul vento in un intervallo di tempo indicato nella richiesta del client.
    Il
    protocollo di comunicazione dovrà essere affidabile e orientato alla connessione.
  2. Un drone espone la propria posizione rappresentandoli attraverso 3 valori floating-point a 32 bit, che indicano la latitudine, la longitudine e l’altitudine. Per fare ciò il drone implementa un server UDP che risponde alle richieste ricevute sulla porta 9999. Le postazioni client a terra che vogliono sapere qual è la posizione del drone, dovranno inviare una richiesta al drone che dovrà rispondere entro un secondo, altrimenti la richiesta si considera fallita. Si progetti il protocollo comunicativo corrispondente facendo tutte le ipotesi aggiuntive che si ritengono necessarie, purché siano opportunamente giustificate.
  3. I dispositivi domotici di nuova generazione (punti luce, elementi di condizionamento climatico, prese di alimentazione per elettrodomestici, ecc.) si connettono alla rete WiFi e vengono comandati mediante datagrammi UDP indirizzati alla porta 23365.

Tutti i dispositivi possono accettare due tipi di comandi:

  • un comando per accendere il dispositivo dopo un certo numero di secondi;
  • un comando per spegnere il dispositivo dopo un certo numero di secondi.

Per entrambi i comandi si pensi ad una modalità per effettuare l’accensione o lo spegnimento immediato appena ricevuto il relativo comando.

Il protocollo di comunicazione deve essere confermato, quindi il dispositivo che ha ricevuto uno dei due comandi precedenti dovrà inviare una conferma al programma mittente. Inoltre si dovrà prevedere un controllo di errore nel caso il comando fosse stato rifiutato per qualsiasi ragione.

Si progetti il protocollo comunicativo corrispondente facendo tutte le ipotesi aggiuntive che si ritengono necessarie, purché siano opportunamente giustificate.

Il seguente link (in inglese qui) potrà esservi utile per migliorare il protocollo.

Aspetti progettuali di un protocollo di comunicazione

  1. Dati i seguenti messaggi scambiati tra un client ed un server che usino il protocollo TFTP per lo scambio di file, individuare e spiegare quali degli aspetti progettuali di un protocollo di comunicazione sono previsti, considerando che tutti quelli considerabili sono:
  1. indirizzamento;
  2. frammentazione e riassemblaggio;
  3. incapsulamento;
  4. controllo della connessione;
  5. servizio confermato o non confermato;
  6. controllo degli errori;
  7. controllo del flusso;
  8. multiplexing;
  9. servizi di trasmissione.

TFTP Formats

  Type   Op #     Format without header

         2 bytes    string   1 byte     string   1 byte
         -----------------------------------------------
  RRQ/  | 01/02 |  Filename  |   0  |    Mode    |   0  |
  WRQ    -----------------------------------------------
         2 bytes    2 bytes       n bytes
         ---------------------------------
  DATA  | 03    |   Block #  |    Data    |
         ---------------------------------
         2 bytes    2 bytes
         -------------------
  ACK   | 04    |   Block #  |
         --------------------
         2 bytes  2 bytes        string    1 byte
         ----------------------------------------
  ERROR | 05    |  ErrorCode |   ErrMsg   |   0  |
         ----------------------------------------

Initial Connection Protocol for reading a file

  1. Host  A  sends  a  "RRQ"  to  host  B  with  source= A's TID, destination= 69.

  2. Host B sends a "DATA" (with block number= 1) to host  A  with source= B's TID, destination= A's TID.

  1. Considerando il protocollo TIME, individuare e spiegare quali degli aspetti progettuali di un protocollo di comunicazione sono in esso previsti previsti, considerando che tutti quelli considerabili sono:
  1. indirizzamento;
  2. frammentazione e riassemblaggio;
  3. incapsulamento;
  4. controllo della connessione;
  5. servizio confermato o non confermato;
  6. controllo degli errori;
  7. controllo del flusso;
  8. multiplexing;
  9. servizi di trasmissione.


Esercizi su XML, Java parser e Web service

XML

  1. Si vuole definire un formato per l’interscambio dati relativo allo stato dei prestiti dei libri di una biblioteca. Il file scambiato specifica la lista degli utenti per ciascuno dei quali si indicano il nominativo (string), il numero di tessera (integer) e la lista dei libri che ha in prestito. Per ciascun libro è indicato il codice del catalogo (string) e la data di scadenza del prestito (date). Si proponga la struttura XML necessaria, mostrando un esempio. Si rappresenti l’XML creato con l’albero DOM[3] corrispondente.
  2. Dato il seguente albero DOM, scrivere il corrispondente file XML.
  3. Si vuole definire un formato per l’interscambio dati relativo alle chiamate di soccorso di una centrale operativa. Il file scambiato specifica la lista delle chiamate. Ciascuna chiamata è caratterizzata da un timestamp (dateTime), dal numero di telefono da cui è stata ricevuta (string), dal codice dell’operatore (integer). Alla chiamata è inoltre associata una lista di segnalazioni. Per ciascuna segnalazione è specificato il luogo (string), la descrizione (string) e il livello di rischio (integer). Si proponga la struttura XML necessaria, mostrando un esempio. Si rappresenti l’XML creato con l’albero DOM corrispondente.
  4. Dato il seguente albero DOM, scrivere il corrispondente file XML.
  5. Si vuole definire un formato per l’interscambio dati relativo alla gestione di un insieme di cartelloni pubblicitari elettronici. Il file scambiato specifica la lista dei cartelloni. Ciascun cartellone è identificato da un codice (integer), dalla città (string), dalla posizione (string), dall’indirizzo IP (string). Ad ogni cartellone è inoltre associata una lista di annunci. Per ciascun annuncio è specificata l’ora di inizio per la visualizzazione (time), l’ora di fine (time) e il testo (string). Si proponga la struttura XML necessaria, mostrando un esempio. Si rappresenti l’XML creato con l’albero DOM corrispondente.
  6. Dato il seguente albero DOM, scrivere il corrispondente file XML.
  7. Si vuole definire un formato per l’interscambio dati relativo alle rilevazioni di inquinamento acustico di una città. Il file scambiato specifica la lista dei punti di misura attivi. Ciascun punto di misura è identificato da un codice numerico (integer) e ha associate le coordinate geografiche (string, es. “43.318423, 11.331361”), la data di installazione del sensore (date), la precisione (decimal), la lista delle misure effettuate e la lista degli interventi di taratura. Per ogni misura si specifica il momento in cui è stata effettuata (dateTime) e il valore misurato (decimal). Per ogni intervento di taratura si indicano la data (date), il nome del tecnico che ha effettuato l’operazione (string) e una eventuale nota (string). Si proponga la struttura XML necessaria, mostrando un esempio. Si rappresenti l’XML creato con l’albero DOM corrispondente.
  8. Si implementi un parser in Java che utilizzi la tecnica DOM per il seguente documento XML, che riporta le informazioni relative ad un file in cui vengono memorizzati i dati relativi ai download effettuati su una serie di server. Il parser dovrà scorrere l’albero DOM utilizzando i nomi dei tag (Esempio 1) e visualizzare, per ogni server, i dati relativi ai vari download effettuati.
    <file name="pippo" dimension="20.0" type="pdf" >
     
    <servers>
         
    <server ip="1.1.1.1" creationDate="Sun Jan 15 15:19:08 CET 2017"   
             
    totalDownload="2" >
               
    <downloads>
               
    <download date="Sun Jan 15 15:19:08 CET 2017" 
                 
    ip="110.234.23.124" speed="10.5" result="OK" />
                 
    <download date="Sun Jan 15 15:19:08 CET 2017" 
                 
    ip="110.234.23.124" speed="10.5" result="OK" />
               
    </downloads>
         
    </server>
         
    <server ip="22.22.1.1" creationDate="Sun Jan 15 15:19:08 CET 2017" 
             
    totalDownload="1" >
               
    <downloads>
                 
    <download date="Sun Jan 15 15:19:08 CET 2017" 
                   
    ip="110.111.23.124" speed="15.5" result="OK" />
               
    </downloads>
         
    </server>
     
    </servers>
    </file>
  9. Si implementi un parser in Java che utilizzi la tecnica DOM per un qualsiasi documento XML, come ad esempio quello dell’esercizio precedente che riporta le informazioni relative ad un file in cui vengono memorizzati i dati relativi ai download effettuati su una serie di server. Il parser dovrà scorrere l’albero DOM senza utilizzare i nomi dei tag (Esempio 2 o 3) e visualizzare le informazioni in esso contenute.

Java parser

  1. Implementare in Java un parser per un XML che descriva delle figure geometriche all’interno di una finestra.

Il file XML deve descrivere le seguenti figure geometriche:

  • linea, indicando primo punto, secondo punto, colore e z-order;
  • ellisse (cerchio), indicando punto iniziale, punto finale, lunghezza, altezza, colore e z-order;
  • rettangolo (quadrato), indicando punto iniziale, punto finale, lunghezza, altezza, colore e z-order;
  • poligono, indicando punto iniziale, punto finale, numero di lati, lunghezza, altezza, colore e z-order.
  1. Implementare un progetto in Java che usando il parser implementato nell’esercizio precedente disegni in una finestra le figure geometriche descritte nel file XML.
  2. bla bla

Esercizi di progettazione di architetture distribuite[4]

Voli low cost

Una compagnia aerea ha una serie di voli low cost fra capitali europee. Per ogni tratta sono noti la capitale di partenza, la capitale di arrivo,  i giorni della settimana in cui si tiene (ad esempio lunedì, mercoledì e venerdì), la capienza dell’aereo (si suppone che su una tratta ci siano sempre aerei con la stessa capienza), l’orario e il prezzo base. Si progetti il Web service che permetta le operazioni CRUD sulle tratte e il relativo client che lo interroga.

Esempio di operazioni

Richiesta di tutte le tratte

GET http://localhost:8080/Esercitazione2

Richiesta della tratta con id = 5

GET http://localhost:8080/Esercitazione2/5

Inserimento di una nuova tratta

POST http://localhost:8080/Esercitazione2

dati inviati dal POST in formato XML

<tratta>
 <partenza>Roma</partenza>
 <arrivo>Vienna</arrivo>
 <giorni>
 
  <giorno value="1"/>
 
  <giorno value="3"/>
 </giorni> <!-- 1 è domenica (Calendar di java) -->
 <capienza value="30"/>
 <orario value="14.45"/>
 <prezzo value="35" />

</tratta>

   

Modifica dei dati della tratta con id = 5. I dati modificati sono evidenziati in grassetto.

PUT http://localhost:8080/Esercitazione2  

<tratta id="5">

  <partenza>Roma</partenza>
 <arrivo>Vienna</arrivo>
 <giorni>
 
  <giorno value="1"/>
 
  <giorno value="3"/>
 </giorni> <!-- 1 è domenica (Calendar di java) -->
 <capienza value="30"/>
 <orario value="14.30"/>
 <prezzo value="40" />
</tratta>

Eliminazione della tratta con id = 5

DELETE http://localhost:8080/Esercitazione2/5


MyShow

La nuova società MyShow vuole fornire via Internet un nuovo servizio agli utenti registrati sul suo sito. Un utente registrato, dopo aver fornito le credenziali di accesso al sito, seleziona una città per ricevere la lista dei film proiettati.

Selezionando uno dei cinema elencati, l’utente otterrà la lista dei film proiettati nella giornata con le relative informazioni per ogni proiezione (titolo del film, orari di proiezione, ecc.)

Per fornire l’elenco dei cinema, il sito della compagnia MyShow utilizza un servizio di terze parti offerto dalla compagnia MovieDB, che per ogni cinema di una data città fornisce il nome del cinema, l’indirizzo, il numero di telefono, l’e-mail e gli orari di apertura. Inoltre, relativamente alle proiezioni dei singoli cinema, il servizio offre l’elenco di tutti i film proiettati, e per ogni film fornisce il titolo, la descrizione, il rating, la durata, gli orari di proiezione e il periodo di proiezione.

Si progetti una architettura distribuita basata sulla tecnologia dei Web service REST utilizzando le servlet, che implementi il servizio offerto dalla compagnia MovieDB alla società MyShow, e il relativo servizio offerto da quest’ultima ai suoi utenti.

Il progetto dovrà comprendere l’architettura complessiva del sistema suddivisa in tier, dei quali si dovrà fornire una rappresentazione grafica e una descrizione di massima dei tier coinvolti e della relativa funzione, considerando i punti di seguito indicati.

  1. Resource Management Layer (Data Layer, Back End):
  1. progettare il database gestito dalla compagnia MovieDB dei cinema nelle relative città e dei film in essi proiettati;
  2. progettare il database degli utenti gestito dalla compagnia MyShow.
  1. Presentation Layer (Front End):
  1. progettare l’interfaccia della pagina Web del servizio offerto dalla società MyShow che dovrà prevedere l’autenticazione o la registrazione dell’utente;
  2. progettare l’interfaccia con cui l’utente, una volta effettuato il login, selezionerà una città per ottenere l’elenco dei cinema e dei film con le informazioni associate;
  1. Business Logic Layer (Application Layer, Logic Layer):
  1. la descrizione funzionale della servlet utilizzata dalla società MyShow per autenticare gli utenti;
  2. la query SQL utilizzata dalla compagnia MovieDB per ottenere l’elenco dei cinema di una città (con tutte le informazioni per raggiungerli) e l’elenco dei film proiettati in ognuno di essi (con tutti i dati associati) da inviare successivamente a MyShow;
  3. la descrizione del Web service offerto dalla compagnia MovieDB alla società MyShow indicando:
  1. la descrizione funzionale del Web service REST, implementato tramite servlet, esposto dalla compagnia MovieDB per offrire il servizio di ricerca richiesto dalla società MyShow;
  2. il metodo HTTP utilizzato per invocarlo secondo l’architettura REST;
  3. l’URL usato per l’invocazione;
  4. un esempio di file XML restituito dal servizio.

Infine si proponga e si illustri un progetto di massima del sistema hardware/software che comporti la installazione del server web:

  • presso la compagnia MyShow
  • in hosting presso un provider ISP.

Per ciascun scenario si illustrino le tecniche di sicurezza che rendono sicuro l'accesso al server.

Se utilizzato durante le lezioni di informatica, o durante gli anni precedenti, potrete illustrare la collaborazione fra i vari elementi del sistema distribuito utilizzando dei diagrammi UML[5].

Realizzazione

Si realizzi un prototipo funzionante del sistema sopra progettato. Se possibile si utilizzino tanti computer quanti sono i sistemi informativi coinvolti.

Sviluppi futuri

  1. Sviluppare una app su Android per l’offerta del servizio di MyShow.
  2. Permettere di restringere la ricerca del cinema nell’ambito di una distanza stabilita dall’utilizzatore dell’app.

Centro assistenza

Un’azienda produttrice di automobili ha circa 10000 centri di assistenza distribuiti in tutto il mondo. Ogni cliente che acquista un’automobile può richiedere la manutenzione della stessa in garanzia nel caso in cui essa presenti dei problemi di funzionamento. Tutte le spese relative alla gestione della manutenzione dell’automobile sono a totale carico dell’azienda produttrice.

Per consentire una migliore integrazione tra la dirigenza dell’azienda ed i centri di assistenza, l’azienda permette ai centri di poter accedere rapidamente ed in tempo reale ai dati principali riguardanti il veicolo che necessita assistenza. Tali dati comprendono, ad esempio, i dati del proprietario, la validità del contratto di assistenza, gli interventi di manutenzione precedenti per quel veicolo, i difetti frequenti riscontrati per il modello di veicolo, eccetera.

L’azienda ha quindi due necessità:

  1. raccogliere informazioni sugli interventi effettuati da parte dei centri di assistenza;
  2. fornire a tali centri, nel momento in cui si presenta un veicolo, tutte le informazioni necessarie.

I centri di assistenza, nei vari continenti, possiedono ognuno un portale Internet, indipendente da quello dell’azienda, ma che segue un layout comune fornito da essa, attraverso il quale possono offrire alcuni servizi personalizzati ai propri clienti. Il portale è anche usato dal centro di assistenza per accedere al servizio offerto dall’azienda per ottenere le informazioni su un’automobile o per inviare i dati di un nuovo intervento effettuato sull’auto di un cliente.

Si progetti il sistema descritto, facendo tutte le ipotesi aggiuntive e prevedendo una architetture multi-tier, considerando tutti i punti seguenti.

  1. Presentation Layer (Front End):
  1. progettare l’interfaccia delle pagine Web di un generico portale che permetta ad un centro di assistenza di autenticarsi, gestendo anche gli eventuali errori;
  2. progettare l’interfaccia della pagina Web per la richiesta dei dati di un’automobile in manutenzione presso il centro di assistenza;
  3. progettare l’interfaccia della pagina Web che visualizzi i dati dell’auto richiesta;
  4. progettare l’interfaccia della pagina Web che permetta di inserire ed inviare i dati di manutenzione effettuati su un’auto.
  1. Resource Management Layer (Data Layer, Back End) costituito da un database gestito dall’azienda produttrice, che descriva le realtà seguenti:
  1. i clienti che hanno acquistato un’auto dell’azienda produttrice;
  2. le automobili prodotte dall’azienda;
  3. gli interventi effettuati sull’auto di un cliente da parte del centro di assistenza;
  4. i centri di assistenza sparsi nel mondo;
  1. Business Logic Layer (Application Layer, Logic Layer):
  1. la query SQL utilizzata  dal centro di assistenza per effettuare il login nel portale dell’azienda;
  2. la query SQL utilizzata  dal centro di assistenza per ottenere tutti i dati dell’auto di un cliente;
  3. la query SQL utilizzata  dal centro di assistenza per aggiungere dati nel database dell’azienda riguardanti un nuovo intervento effettuato sull’auto di un cliente;
  4. la descrizione del Web service REST offerto dall’azienda produttrice ai centri di assistenza per poter eseguire tutte le query SQL descritte precedentemente, indicando per ognuna di esse:
  1. il metodo HTTP da utilizzare secondo l’architettura REST;
  2. l’URL usato per l’invocazione, secondo i principi dell’architettura REST;
  3. un esempio di file XML restituiti dal servizio o inviati dal centro di assistenza.

Se utilizzato durante le lezioni di informatica, o durante gli anni precedenti, potrete illustrare la collaborazione fra i vari elementi del sistema distribuito utilizzando dei diagrammi UML[6].

Realizzazione

Si realizzi un prototipo funzionante del sistema sopra progettato. Se possibile si utilizzino tanti computer quanti sono i sistemi informativi coinvolti.


GTT (trasporre)

La società GTT (Gruppo Trasporti Timbuktu) ha recentemente integrato una serie di altre società locali di trasporti dello stato di Mali. Come parte della nuova strategia gestionale, la GTT intende fornire ai propri utenti un servizio centralizzato di consultazione degli orari, di calcolo dei percorsi e di acquisto dei documenti di viaggio (biglietti).

La società GTT costruisce quindi un proprio sistema informativo, accessibile dai propri utenti mediante un portale web, che offre le funzioni citate. Ovviamente le informazioni riguardo i tragitti, gli orari, i prezzi sono di competenza delle singole società locali di trasporti, ciascuna delle quali ha nel tempo sviluppato il proprio sistema informativo.

Descrivere una possibile modalità di integrazione (quale tecnologia usare, quali dati scambiare, dove memorizzare i dati, ...) tra i sistemi informativi della GTT e quelli delle società locali di trasporti, in grado di supportare le funzionalità descritte (consultazione degli orari, calcolo automatico dei percorsi, acquisto dei documenti di viaggio). In particolare si consideri che per il calcolo dei percorsi è necessario integrare i dati delle diverse società locali, proponendo anche percorsi “misti”, ossia composti da tratte gestite da società locali distinte.


Dottorato (trasporre)

Gli studenti di Dottorato di Ricerca, nella loro formazione specialistica, devono spesso seguire corsi di dottorato che si tengono presso varie università, anche diverse dalla propria università di iscrizione.

Le Università intendono potenziare il proprio sistema informativo per permettere a tali studenti di trattare anche i corsi presso altre università alla stessa stregua dei corsi “interni”. Possiamo supporre che ciascuna università abbia un sistema equivalente al sistema proposto dal Politecnico di Torino, in cui esiste la gestione del carico didattico, prenotazione esami, visione del libretto elettronico, ecc. Tuttavia, possiamo essere certi che le varie università abbiamo implementato il sistema in modi anche molto diversi, sia dal punto di vista dell'interfaccia utente che dal punto di vista delle tecnologie coinvolte.

Descrivere una possibile soluzione al problema dell'integrazione tra i sistemi informativi, che permetta ad uno studente iscritto in una qualsiasi università partecipante di visionare i corsi disponibili, inserirli nel proprio carico didattico, comparire negli elenchi ufficiali visibili al docente, prenotarsi all'esame, ed avere registrato il proprio voto.


Olimpiadi (trasporre)

In vista delle prossime Olimpiadi, il comitato olimpico del paese X intende offrire a tutti i giornalisti (ed in generale ai media interessati) un servizio in tempo reale con i risultati di tutti gli eventi sportivi in corso.

In particolare, dovranno essere disponibili in modalità distribuita: i calendari delle gare, i risultati di ciascuna gara (in cui per ciascun atleta o squadra partecipante è indicato il punteggio o misura significativa), ed il “medagliere” (le medaglie assegnate ai vari atleti o squadre, divise per nazione e per tipo di medaglia).

Si tenga presente che anche l’Olimpiade stessa è un evento “distribuito”, poiché le gare si svolgono in luoghi geograficamente anche molto lontani; per questo motivo occorre identificare anche la modalità migliore di aggiornamento delle informazioni da parte degli organizzatori e dei giudici.

Si progetti, per conto del comitato olimpico del paese X, il sistema informativo che dovrà gestire la pubblicazione di tali dati e la relativa gestione ed aggiornamento.


Grande Fratello (trasporre)

Il Ministero delle Finanze intende investire in un sistema informativo in grado di combattere alla radice il fenomeno dell’evasione fiscale. Il principio guida di tale riforma –denominata Grande Fratello– è che esistono già molti sistemi informativi “parziali”, alcuni pubblici (catasto, anagrafe dei residenti, motorizzazione civile, ...) ed altri privati (banche, assicurazioni, finanziarie, ...). Il Ministero ritiene che “incrociando” tali dati sia possibile rilevare molte “anomalie” o situazioni sospette, grazie al fatto che tutti i sistemi informativi fanno capo comunque all’identificazione mediante codice fiscale (si tralasci il caso degli evasori totali o di coloro che si servono di prestanomi che non verrebbero comunque identificati da questo sistema).

In particolare, il Ministero dovrà poter consultare, in ogni momento, i dati relativi ad un determinato contribuente nelle varie base dati disponibili, ciascuna delle quali ovviamente conterrà dati di natura diversa. Deve inoltre essere possibile, da parte da qualsiasi ente, “segnalare” un determinato contribuente, qualora l’ente abbia il sospetto di comportamenti anomali.

Si progetti, per conto del Ministero delle Finanze, il sistema informativo che dovrà gestire la condivisione di tali dati ed il meccanismo di segnalazione. Le scelte progettuali dovranno mirare alla minimizzazione dei costi per i vari sistemi informativi che dovranno essere adattati ed integrati, mentre non vi sono praticamente vincoli di complessità sul sistema del Ministero.


UVI (trasporre)

Una grande catena di supermercati intende realizzare un sistema di videosorveglianza intelligente, in grado di osservare i comportamenti degli utenti nei propri punti vendita e dedurne informazioni di vario tipo (ad esempio, l’interesse relativo ai prodotti esposti, oppure sul rischio di taccheggio).

Il sistema è basato su una serie di Unità Video Intelligenti (UVI) dotate ciascuna di una telecamera e di un computer collegato alla rete. Ciascuna UVI (ve ne possono essere diverse in ciascun punto vendita) analizza il flusso di immagini provenienti dalla telecamera, e ne estrae alcuni dati sintetici significativi. Ad esempio, associa ad ogni persona diversa un diverso ID numerico autogenerato, rappresenta tale persona mediante delle caratteristiche biometriche in grado di riconoscere se la stessa persona compare nel campo visivo di più UVI, identifica una serie di “gesti” o “posture” (es: guarda, prende, confronta, ...) per ciascuna persona. In aggiunta, ciascuna UVI salva anche sul proprio hard disk i dati completi (tutti i fotogrammi e tutti i dati da essi estratti) relativi alle ultime 48 ore.

L’insieme di tutti gli UVI è collegato con il Centro di Elaborazione della grande catena, il quale è deputato a ricevere le informazioni sintetiche da tutti gli UVI supervisionati ed a compiere delle ulteriori elaborazioni sulle informazioni ricevute. Per alcune di tali elaborazioni (es. tracciamento del percorso di un cliente tra i campi visivi dei vari UVI) sono sufficienti i dati sintetici forniti dagli UVI. Per altre elaborazioni (es. invio alla polizia del filmato di un potenziale taccheggiatore) sono invece necessari i dati completi.

Ovviamente le capacità trasmissive di Internet non permettono in alcun modo la trasmissione continua, completa ed in tempo reale dei dati completi da parte di tutti gli UVI contemporaneamente, mentre invece per i dati sintetici non vi sono problemi di banda.

Si progetti, per conto della grande catena, il sistema informativo che dovrà gestire la raccolta dei dati dagli UVI ed il meccanismo di comunicazione tra questi ultimi ed il centro di elaborazione. Le scelte progettuali dovranno mirare alla compatibilità con la banda disponibile su Internet, permettendo però una rilevazione tempestiva di eventuali comportamenti anomali.


Bibliografia e sitografia

I socket e la comunicazione in rete

Meini G., Formichi F., Tecnologie di progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2017

V. Auletta, Corso di Reti di calcolatori, http://www.di.unisa.it/professori/auletta/DIDATTICA/RETI_04/, autunno 2003

M. Maggini, Corso di Reti di calcolatori, http://www.dii.unisi.it/~maggini/Teaching/reti_di_calcolatori.html, a.a. 2015/2016

Università di Verona, Dipartimento di Informatica, Scrittura di applicazioni di rete, http://www.di.univr.it/documenti/OccorrenzaIns/matdid/matdid546139.pdf, ultimo accesso gennaio 2017

D. J. Dubois, Programmazione di rete in Java, http://home.deib.polimi.it/dubois/provafinale/rete.pdf, Politecnico di Milano, ultimo accesso gennaio 2017

G. Anastasi, N. Iardella, Corso di Reti Informatiche, http://www2.ing.unipi.it/~a008149/corsi/reti/materiale.html, Università di Pisa, ultimo accesso gennaio 2017

I sistemi distribuiti: modelli architetturali hardware e software

P. Camagni, R. Nikolassy, Tecnologie e progettazione di sistemi informatici e di telecomunicazioni, vol. 3, ed. Hoepli, 2014.

2veritasium, Transistors & The End of Moore's Law, https://youtu.be/rtI5wRyHpTg

A337 | S400, 3 Tier Client Server Architecture, https://youtu.be/jJYv-nfkMXk?list=PLmPpJG5-RKf0RUQ7VYjHn6pnoWT2__4CM

Barbero T., Clegg J., Programmare Percorsi CLIL, Carocci, Roma 2005.

Bubble.us, https://bubbl.us/

CLIL Media, http://clilmedia.com/

Cmap, http://www.cmaptools.com/

Christopher Kalodikis, Client-server model, https://youtu.be/ntp9XZ4hOrY?list=PLmPpJG5-RKf0RUQ7VYjHn6pnoWT2__4CM

V. Cardellini, Classificazione delle Architetture Parallele, Corso di Sistemi Distribuiti a.a. 2009/2010, Università degli Studi di Roma “Tor Vergata”, Facoltà di Ingegneria

English tutorial, http://www.englishpage.com/

G. Coulouris, J. Dollimore, T. Kindberg, G. Blair, Distributed system, Concept and Design, Fifth Edition, Addison-Wesley, May 2011, http://www.cdk5.net/wp/

Games to learn English, http://www.engames.eu/

Google, http://www.google.it

Grewal, N-Tier Architecture for kids, https://youtu.be/8gfTBQhh1kM?list=PLmPpJG5-RKf0RUQ7VYjHn6pnoWT2__4CM

C. Kalodikis, Client-Server Model, https://youtu.be/IOnWn5u-sXE

Kurzgesagt – In a Nutshell, Quantum Computers Explained – Limits of Human Technology, https://youtu.be/JhHMJCUmq28

Linking Words for IELTS Speaking: Word List & Tips, http://ieltsliz.com/linking-words-for-ielts-speaking/

ovp , How Cloud Computing Work, https://youtu.be/DGDtujmOBKc

PieterExplainsTech, UDP and TCP: Comparison of Transport Protocols, https://youtu.be/Vdc8TCESIg8

S. Haridi, Distributed Algorithms, https://www.youtube.com/playlist?list=PL700757A5D4B3F368

Regis University CPS SCIS, Middleware Concepts, https://youtu.be/S8sgGXUqw30?list=PLmPpJG5-RKf0RUQ7VYjHn6pnoWT2__4CM

Regis University CPS SCIS, Middleware Architecture, https://youtu.be/E2jFOTDK0tY?list=PLmPpJG5-RKf0RUQ7VYjHn6pnoWT2__4CM

The m-Power Platform, n-Tier Architecture Explained, https://youtu.be/KlHvRKSH4pk

Udacity, Georgia Tech, Advanced Operating Systems part 2 of 4, https://www.youtube.com/playlist?list=PLAwxTw4SYaPm4vV1XbFV93ZuT2saSq1hO

Udacity, Georgia Tech, HPCA: Part 5, https://youtu.be/WKXbvhkzBUo?list=PLmPpJG5-RKf0RUQ7VYjHn6pnoWT2__4CM

Veritasium, How Does a Quantum Computer Work?, https://youtu.be/g_IaVepNDT4

WhatIs.com, http://whatis.techtarget.com/

Wikipedia, The Free Encyclopedia, https://www.wikipedia.org/

Java e XML

P. Camagni, R. Nikolassy, Tecnologie e progettazione di sistemi informatici e di telecomunicazioni, vol. 3, ed. Hoepli, 2014

G. Meini, F. Formichi, Tecnologie e progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2014

Wikipedia, The Free Encyclopedia, https://www.wikipedia.org/

R. Golia, Design pattern per esempi: i GoF creazionali, Microsoft® Development Network, https://msdn.microsoft.com/it-it/library/cc185067.aspx#ID0ECBAC, novembre 2006, ultima visita gennaio 2017

TutorialsPoint, Design Pattern - Factory Pattern, https://www.tutorialspoint.com/design_pattern/factory_pattern.htm, ultima visita gennaio 2017

B. McLaughlin & J. Edelson, Java & XML, 3rd edition, O’Reilly, 2006

Mkyong.com, How to read XML file in Java – (DOM Parser), http://www.mkyong.com/java/how-to-read-xml-file-in-java-dom-parser/, ultima visita gennaio 2017

HTTP e Servlet

P. Camagni, R. Nikolassy, Tecnologie e progettazione di sistemi informatici e di telecomunicazioni, vol. 3, ed. Hoepli, 2014

w3schools.com, HTTP Methods, http://www.w3schools.com/tags/ref_httpmethods.asp, ultimo accesso gennaio 2017

JavaTpoint, Web Terminology, http://www.javatpoint.com/web-terminology, ultimo accesso gennaio 2017

Wikipedia, L’enciclopedia libera, https://it.wikipedia.org

Lifewire, HTTP Status Codes, https://www.lifewire.com/http-status-codes-2625907, 28 novembre 2016

Mikalai Zaikin, IBM WebSphere Application Server Network Deployment V8.0 Core Administration Guide, http://java.boot.by/ibm-317/index.html, agosto 2013

Jayson Online, Configuring Apache in front of JBoss Application Server Using mod_jk, http://www.jaysonjc.com/programming/configuring-apache-in-front-of-jboss-application-server-using-mod_jk.html, 19 aprile 2011

Web Service REST

Chiarelli A., RESTful Web Services – La Guida, http://www.html.it/guide/restful-web-services-la-guida/,  HTML.it, 6 febbraio 2012

G. Meini, F. Formichi, Tecnologie e progettazione di sistemi informatici e di telecomunicazioni, vol. 3, Zanichelli, 2014

Java tutorial for beginners, http://www.java2blog.com/2013/03/web-service-tutorial.html, ultimo accesso gennaio 2017

ORACLE, Java™ Platform, Standard Edition 7 API Specification, https://docs.oracle.com/javase/7/docs/api/, ultimo accesso gennaio 2017

Stack Overflow, http://stackoverflow.com/

Javarevisited, Java Synchronization Tutorial : What, How and Why?,
http://javarevisited.blogspot.it/2011/04/synchronization-in-java-synchronized.html
aprile 2011, ultimo accesso febbraio 2017

Java Brains, Developing RESTful APIs with JAX-RS, https://www.youtube.com/playlist?list=PLqq-6Pq4lTTZh5U8RbdXq0WaYvZBz2rbn, ultimo accesso marzo 2017

L. Petrosino, Luca’s blog, http://luca-petrosino.blogspot.it/, ultimo accesso marzo 2017

Team SGTEAM, Progetto MONK - Gestione del protocollo della corrispondenza della biblioteca di Santa Giustina, http://www.dei.unipd.it/~fantozzi/MONK/descr_progetto.html, 30 settembre 1999, ultimo accesso marzo 2017

Maria Lăiu, Botnaru Elvis, Nicolae Abăcioaiei, Ionuț Stincescu and Dumitru Lesnic, pentastagiu, ultrashop - Wiki, https://github.com/pentastagiu/ultrashop/wiki, ultimo accesso marzo 2017

F. Corno, D. Bonino, 01KTF - Architetture distribuite per i sistemi infomativi aziendali, https://elite.polito.it/teaching/past-courses/19-01ktf?showall=,  e-lite research group, 9 marzo 2008, ultimo accesso aprile 2017

Agile Modeling (AM) Home Page, Effective Practices for Modeling and Documentation, http://agilemodeling.com/, ultimo accesso aprile 2017

The Unified Modeling Language, http://www.uml-diagrams.org/, ultimo accesso aprile 2017

IBM developerWorks®, https://www.ibm.com/developerworks/, ultimo accesso aprile 2017

WebSequenceDiagrams, https://www.websequencediagrams.com/, ultimo accesso aprile 2017

StarUML, http://staruml.io/, ultimo accesso agosto 2017

Violet UML Editor, http://alexdp.free.fr/violetumleditor/page.php, ultimo accesso agosto 2017


[1] I sistemi legacy (legacy system) identificano i sistemi obsoleti presenti in una azienda ereditati dalle prime fasi di informatizzazione della stessa. Spesso rivestono ruoli critici e possono anche avere dimensioni notevoli, ma nonostante la possibile lunga storia di interventi di manutenzioni, non sono mai stati rimpiazzati perché sostanzialmente funzionano ancora e, probabilmente, l’attività svolta non è ancora stata sostituita da tecnologie più recenti.

[2] Tassonomia di Flynn

[3] Document Object Model.

[4] Per questi esercizi si ringrazia il Prof. Giuliano Bellucci per la fantasia nell’inventarli e il Prof. Fulvio Corno del Politecnico di Torino che ha reso disponibile sul Web il materiale del corso di Architetture distribuite per i sistemi informativi aziendali dell’a.a. 2008/2009. Gli esercizi sono stati riadattati per un corso di scuola secondaria di secondo grado.

[5] Introduction to the Diagrams of UML 2.X

  The Unified Modeling Language

  An introduction to the Unified Modeling Language
 
WebSequenceDiagrams

[6] Introduction to the Diagrams of UML 2.X

  The Unified Modeling Language

  An introduction to the Unified Modeling Language
 
WebSequenceDiagrams