Questa versione: Protocollo1.1
Ultima versione: Protocollo1.1
Versione Precedente: Protocollo10
Autori: FabioVitali, AngeloDiIorio, SilvioPeroni, FrancescoPoggi
Questo protocollo nasce all’interno del progetto City Notifier del corso di Tecnologie Web 2012/2013. L'obiettivo del progetto è di sviluppare una piattaforma per la notifica di problemi, situazioni particolari o emergenze all'amministrazione pubblica o agli altri utenti della piattaforma.
Il concetto primario gestito dal sistema è la notifica di una situazione, ossia di una circostanza che un utente del sistema intende condividere in quanto di interesse pubblico. Ogni notifica è associata a diverse informazioni sulla natura dell'evento da segnalare, il luogo e il tempo della segnalazione. Si definisce evento un'aggregazione di notifiche riferite alla medesima situazione e manipolata dal server in un unico oggetto.
L’architettura City Notifier prevede due componenti principali: client (che consultano gli eventi del sistema, e possono a loro volta notificarne di nuovi o segnalare modifiche dello stato di quelli presenti) e server (che si occupano di raccogliere le notifiche segnalate dai client, di manipolarle opportunamente e di fornire le informazioni sugli eventi). Ogni client comunica direttamente con il proprio server di riferimento, il quale si occuperà di rispondere con le informazioni che ha localmente e successivamente di integrarle con quelle mantenute dagli altri server qualora sia opportuno.
Questo documento è un aggiornamento della versione redatta da FabioVitali, AngeloDiIorio, SilvioPeroni, FrancescoPoggi. Deve essere utilizzato come materiale di riferimento per il progetto CityNotifier per garantire l’interoperabilità fra i gruppi.
City Notifier è un sistema federato per la notifica dell'evoluzione di eventi di interesse pubblico. È quindi fondamentale associare un'identità ad ogni utente della piattaforma, e per ognuno di essi gestirne autorevolezza e credibilità. Inoltre, vista la natura distribuita del sistema, è importante implementare meccanismi per la corretta gestione delle notifiche (aggregazione di notifiche vicine sia temporalmente che a livello geografico, evoluzione nel tempo e sbiadimento, unificazione e risoluzione di eventi gestiti da altri sever, ecc.).
Il sistema è composto da un database di notifiche e eventi; questi ultimi, già aggregati, vengono presentati all'utente sotto forma di lista, tabella o cartina geografica. In particolare il database può presentare eventi di questi tipi, a loro volta suddivisi in sottotipi:
Ogni gruppo ha l'obbligo di implementare almeno una versione per PC e una versione mobile (iPhone, iPad o dispositivi Android) del client, e almeno un server. Per ogni gruppo, i sever hanno degli identificativi ben precisi che sono reperibili in determinati URL (pubblicati sulla pagina del gruppo, e raccolti in un catalogo accessibile via web), come descritto nella sezione 4.
CN è un protocollo HTTP che regola la comunicazione tra un client e un server CityNotifier. Lo stesso protocollo (in particolare le richieste GET di tipo local
, dettagli in seguito) è usato nella comunicazione server-server. Di seguito sono descritte tutte le possibili richieste previste. Le richieste sono progettate secondo l'architettura REST.
Per ogni richiesta è indicato:
È possibile richiedere ad un particolare server, identificato da un URL, delle situazioni coerentemente a dei parametri dati come input dal client.
Nello specifico, il client fa tre tipi di richieste: la prima, sincrona (o anche asincrona, se ad esempio si vuole inserire un sistema di aggiornamento automatico), di tipo local
, richiede i dati locali al server di riferimento; la seconda, asincrona, di tipo remote
, richiede i dati di tutti i server disponibili (e che rispondono entro 5 secondi); infine la terza, asincrona, di tipo local
e ristretta alla posizione attuale del client, richiede gli eventi con status skeptical
, in modo che il server possa interrogare il client riguardo il loro reale status.
http://ltwxxxx.web.cs.unibo.it/richieste?scope=<scope>&type=<type>&subtype=<subtype>&lat=<lat>&lng=<lng>&radius=<radius>&timemin=<timemin>&timemax=<timemax>&status=<status>
dove:
http://ltwxxxx.web.cs.unibo.it/richieste
è l'url del server da contattare. Il campo richieste
è una costante e indica il servizio a cui si è interessati;
<scope>
è la tipologia di richiesta da fare. Il valore, una stringa, può essere o local
o remote
. Nel primo caso, la richiesta deve restituire tutte le informazioni che ha il server in locale. Nel secondo caso, la richiesta deve restituire tutte le informazioni contenute negli altri server;
<type>
è il tipo di situazione che si sta richiedendo. Il valore, una stringa, può essere o all
(se interessano tutti gli eventi a prescindere dal tipo) o uno a scelta tra i seguenti: problemi_stradali
, emergenze_sanitarie
, reati
, problemi_ambientali
, eventi_pubblici
;
<subtype>
è il sottotipo di situazione che si sta richiedendo. Il valore, una stringa, può essere o all
(se interessano tutti gli eventi di un certo tipo a prescindere dal sottotipo) o uno tra quelli elencati di seguito. Se il tipo è problemi_stradali
: incidente
, buca
, coda
, lavori_in_corso
, strada_impraticabile
; se il tipo è emergenze_sanitarie
: incidente
, malore
, ferito
; se il tipo è reati
: furto
, attentato
; se il tipo è problemi_ambientali
: incendio
, tornado
, neve
, alluvione
; se il tipo è infine eventi_pubblici
: partita
, manifestazione
, concerto
;
<lat>
è la latitudine del centro da utilizzare per localizzare la situazione. Valore di tipo FLOAT, con il simbolo "." per separare i decimali;
<lng>
è la longitudine del centro da utilizzare per localizzare la situazione; Valore di tipo FLOAT, con il simbolo "." per separare i decimali;
<radius>
è il raggio di azione (in metri) da considerare per localizzare la situazione a partire dal centro descritto dai due parametri precedenti. Valore di tipo FLOAT, con il simbolo "." per separare i decimali;
<timemin>
è l'inizio dell'intervallo di tempo al quale si è interessati. Il formato è quello dei timestamp UNIX (conversioni da formati "umani" sono da effettuarsi lato client), quindi è un dato di tipo intero;
<timemax>
è la fine dell'intervallo di tempo al quale si è interessati. Il formato è quello dei timestamp UNIX (conversioni da formati "umani" sono da effettuarsi lato client), quindi è un dato di tipo intero;
<status>
è il tipo di status assegnato alla situazione. Il valore, una stringa, può essere all
(se interessano tutte le situazioni a prescindere dallo status) o uno a scelta tra i seguenti: open
, closed
, skeptical
, archived
.
http://ltw1234.web.cs.unibo.it/richieste?scope=local&type=all&subtype=all&lat=28.847607&long=57.084961&radius=15.5&timemin=1368475200&timemax=1368486000&status=open
chiede al server disponibile all'URL http://ltw1234.web.cs.unibo.it/richieste
di restituire tutti gli eventi memorizzati localmente che hanno status aperto, sono situati nell'area avente come centro (28.847607,57.084961) con un raggio di quindici metri e mezzo e che sono stati notificati tra le 20 e le 23 del giorno 13 maggio 2013 (conversione dei timestamp UNIX dei valori "1368475200" e "1368486000"). Per verificare i campi relativi all'intervallo di tempo si utilizza il campo freshness
dell'evento (vedi sezione 5).
Header: Accept: application/json
Body: Vuoto.
Content-type: application/json; charset=utf-8
Body:
Il body è composto da un grande oggetto esterno con campi per riconoscere il server e da una lista di eventi contenuta nel suo campo events.
Un esempio con due eventi:
{ "request_time" : 1368095111, "result" : "Messaggio di servizio", "from_server" : "http://ltw1234.web.cs.unibo.it", "events" : [ { "event_id" : "902438", "type" : { "type" : "problemi_stradali", "subtype" : "incidente"}, "description" : ["ommioddio","come na catapulta","","",""], "start_time" : 1368045665, "freshness" : 1368085800, "status" : "open", "reliability" : 0.8, "number_of_notifications" : 2, "locations" : [ { "lat" : 37.42291810, "lng" : -122.08542120 }, { "lat" : 37.42291810, "lng" : -122.08542120 } ] }, { "event_id" : "459459", "type" : { "type" : "problemi_stradali", "subtype" : "incidente"}, "description" : ["mi hanno tamponato","dottore chiami un dottore","che guaio","descr4","descr5"], "start_time" : 1368105698, "freshness" : 1368106058, "status" : "open", "reliability" : 1.0, "number_of_notifications" : 4, "locations" : [ { "lat" : 37.42291810, "lng" : -122.08542120 }, { "lat" : 37.42291811, "lng" : -122.08542121 }, { "lat" : 37.42291812, "lng" : -122.08542122 }, { "lat" : 37.42291813, "lng" : -122.08542123 } ] } ] }Per quanto riguarda i campi nel dettaglio (i gruppi DEVONO seguire questo formato, vedi sezione 6 per quanto riguarda l'estensibilità):
assiduity
* reputation
) divisa per (2 * number_of_notifications
).
\[
\frac{\sum_{u\in utenti} {(1+ u.assiduity \cdot u.reputation)}}{2 \cdot number\_of\_notification}\]
dove "utenti" è l'insieme degli utenti che hanno notificato l'evento e "assiduity" e "reputation" sono i valori di assiduità e reputazione di quegli utenti. Questo campo indica un generico valore di "affidabilità" dell'esistenza dell'evento e del suo status;http://ltwxxxx.web.cs.unibo.it/segnalazione/
che indica l'url del server da contattare. A livello di logica soltanto l'oggetto "lista di eventi" è considerato una risorsa, la quale può essere consultata e modificata; non è necessario creare una nuova risorsa indirizzabile per ogni singolo evento. Le segnalazioni vengono viste come modifiche (POST, appunto) dell'unico oggetto "lista di eventi".
I parametri della nuova segnalazione sono espressi nel body, come spiegato in seguito.
Header:
Accept: application/json Content-type: application/json; charset=utf-8Body: I parametri del servizio sono indicati, in JSON, usando le seguenti chiavi:
type
è il tipo di situazione che si sta segnalando. I valori legali del sottocampo type
e di quello subtype
sono specificati nella sezione 1 e devono seguire il formato (ad esempio, l'underscore al posto degli spazi) specificato nella sezione 2.1 (togliendo naturalmente "all");
lat
è la latitudine del centro da utilizzare per localizzare la situazione;
lng
è la longitudine del centro da utilizzare per localizzare la situazione;
description
, opzionale, è una descrizione testuale dell'evento.
http://ltw1234.web.cs.unibo.it/segnalazione
chiede al server disponibile all'URL http://ltw1234.web.cs.unibo.it/segnalazione
di aprire una nuova segnalazione di tipo problemi_stradali
, sottotipo incidente
, situata in un preciso punto identificato da una latitudine ed una longitudine, specificando il seguente body:
{ "type" : { "type" : "problemi_stradali", "subtype" : "incidente"}, "lat" : 28.847607 , "lng" : 57.084961 , "description" : "io ho visto tutto" }
Content-type: application/json; charset=utf-8
Body:
Un semplice JSON con due campi. Esempio:
{ "event_id" : "9806", "result" : "nuova segnalazione aperta con successo / segnalazione di un evento già in memoria avvenuta con successo" }Dove:
event_id
è l'id del nuovo evento creato, oppure l'id dell'evento a cui la segnalazione è stata associata se il server ha deciso di accorparla ad un evento che aveva già nel proprio database;
result
è un messaggio che indica il successo o il fallimento dell'operazione, che può anche contenere un'informazione riguardo al fatto che è stato creato un nuovo evento oppure la segnalazione è stata accorpata ad un altro già esistente.
remote
. Il proprio server, infatti, potrebbe non possedere affatto quell'evento (dunque, la mossa più indicata per il client sarebbe "aprire una nuova segnalazione", vedi sezione 2.2).
Metodo: POST
URL: http://ltwxxxx.web.cs.unibo.it/notifica/
che indica l'url del server da contattare.
I parametri della notifica sono espressi nel body, come spiegato in seguito.
Header:
Accept: application/json Content-type: application/json; charset=utf-8Body: I parametri del servizio sono indicati, in JSON, usando le seguenti chiavi:
event_id
è l'id dell'evento da notificare; come per il campo event_id
descritto in 2.1, è una stringa;
status
è lo status da specificare, vedi la nota;
lat
è la latitudine del centro del luogo dove si trova attualmente l'utente;
lng
è la longitudine del centro del luogo dove si trova attualmente l'utente;
description
è l'eventuale descrizione testuale della notifica.
http://ltw1234.web.cs.unibo.it/notifica/
chiede al server disponibile all'URL http://ltw1234.web.cs.unibo.it/notifica
di chiudere la situazione identificata come "9807"
specificando il seguente body:
{ "event_id" : "9807", "status" : "closed", "lat" : 28.847607 , "lng" : 57.084961 , "description" : "non c'è più traffico" }NOTA: Si noti che in questo contesto
status
ammette i valori open
, closed
e archived
(mai skeptical
); open
indica lo stato di perduranza dell'evento, mentre archived
deve poter essere messo solo dagli utenti autorizzati (es. funzionari comunali). I valori di latitudine e longitudine, come sempre FLOAT, sono relativi alla posizione attuale dell'utente e servono per la creazione della lista di punti; la descrizione testuale, infine, è opzionale. Si noti anche che è il server a dedurre dati come il tempo della notifica o la reputazione dell'utente che l'ha fatta e a gestire opportunamente le autorizzazioni.
Content-type: application/json; charset=utf-8
Body:
Un semplice JSON con un unico campo per segnalare eventuali errori.
{ "result" : "notifica inviata con successo" }
http://ltwxxxx.web.cs.unibo.it/login/
Header:
Accept: application/json Content-type: application/json; charset=utf-8Body: Un semplice JSON con due campi, entrambe stringhe, per gestire il login.
{ "username" : "PinoCammino88" , "password" : "xxxxxxxx" }
Content-type: application/json; charset=utf-8
Body:
Un semplice JSON con un unico campo per segnalare eventuali errori.
{ "result" : "login effettuato con successo" }
http://ltwxxxx.web.cs.unibo.it/logout/
Header: Accept: application/json
Body: Vuoto.
Content-type: application/json; charset=utf-8
Body:
Un semplice JSON con un unico campo per segnalare eventuali errori.
{ "result" : "logout effettuato con successo" }
Nel caso in cui una richiesta generi un errore, il servizio DEVE rispondere utilizzando gli appropriati codici HTTP 4xx e 5xx. Le applicazioni DEVONO gestire ogni codice d'errore in maniera appropriata.
Le applicazioni DEVONO gestire almeno questi errori (con relativi codici HTTP):
In aggiunta ai codici d'errore HTTP, il contenuto fornito dal server deve fornire più indicazioni possibili sull'errore generato e fornire suggerimenti su come risolverlo. I servizi sono liberi di usare qualsiasi tipo di dato per il contenuto restituito, tenendo comunque in considerazione la richiesta originaria del client (fornite nell'header Accept o in altro modo).
Ogni gruppo deve inviare i propri dati per permettere la costruzione di un catalogo dei server, un file XML chiamato catalogo, e reperibile all'URL http://vitali.web.cs.unibo.it/TechWeb13/Catalogo. Nel catalogo si trovano coppie di nomi di gruppi e URL (univoco) sul quale risiede il relativo server, secondo questo formato:
<catalogo> <server gruppo="Thank you for coding" url="http://ltw1234.web.cs.unibo.it/" /> <server ... /> ... </catalogo>
In questa sezione viene descritto il modello dei dati da utilizzare per restituire al client i risultati delle richieste fatte verso il server (notifiche già aggregate in eventi).
I dati da gestire devono riguardare luoghi (fisici o virtuali), devono essere geolocalizzabili e devono avere specificati degli orari di apertura e di chiusura. Conseguentemente, i campi che devono essere gestiti sono:
Le informazioni introdotte nelle sezioni precedenti devono essere espresse in JSON (http://tools.ietf.org/html/rfc4627). Le chiavi dei vari oggetti da utilizzare per le informazioni da gestire sono:
events
è una lista di eventi il cui singolo elemento è così descritto:
{ "event_id" : "event085", "type" : { "type" : "problemi_ambientali", "subtype" : "incendio"}, "description" : ["va tutto a fuoco","brucia come l'Inferno","i bambini, nessuno pensa ai bambini","",""], "start_time" : 1368105698, "freshness" : 1368106058, "status" : "open", "reliability" : 1.0, "number_of_notifications" : 3, "locations" : [ { "lat" : 37.42291810, "lng" : -122.08545120 }, { "lat" : 37.42291812, "lng" : -122.08549133 }, { "lat" : 37.42291913, "lng" : -122.08442129 } ] }Per maggiori dettagli sui possibili valori dei campi si consultino le sezioni precedenti, in particolar modo la 2.1.
Per minimizzare l'incoerenza tra gli eventi memorizzati in locale e quelli che arrivano dopo la richiesta remota, abbiamo definito delle linee guida per quanto riguarda la gestione dello status skeptical
, lo sbiadimento degli eventi e l'estensibilità dei campi degli eventi.
Tutti gli eventi passano automaticamente a closed
20 minuti dopo l'ultima segnalazione ricevuta. Fanno eccezione gli eventi di due sottotipi: buca e lavori in corso, che non sbiadiscono (attendono invece di essere chiusi o archiviati da un'autorità).
Un evento passa in stato skeptical
appena una notifica viola la naturale linea temporale aperto->chiuso->archiviato. Come da specifiche, questo scatena la richiesta di conferme ai vari client: quanto tempo fare trascorrere prima di stabilire quale sia la natura della maggioranza delle risposte è a discrezione del server, perché queste richieste vengono inviate in locale; non viene cioè chiesto a un client che ha fatto una richiesta remote
di confermare gli eventi skeptical
di server remoti. Un client, in generale, notifica (con il protocollo descritto nella sezione 2.3) solamente gli eventi memorizzati in locale sul proprio server: se lo vorranno (per rispondere alle richieste remote
) saranno gli altri server a doversi aggiornare sulla situazione.
Non si è voluto descrivere in maniera troppo restrittiva le politiche di accorpamento delle notifiche in eventi, per lasciare ai gruppi maggiore libertà. Per questo, suggeriamo l'idea di non aggiornare in modo permanente i propri eventi aggregandoli con i dati ricevuti dagli altri server: l'accorpamento con i dati "esterni" viene fatto volta per volta, per rispondere a una richiesta remote
, inviando al richiedente un risultato temporaneo - una composizione di eventi - che non viene memorizzato localmente (i dati esterni non contaminano quelli locali).
L'accorpamento di certi dati è piuttosto semplice: ad esempio, per l'aggiornamento del campo reliability
, la presenza del campo number_of_notifications
garantisce un risultato esatto con pochi semplici passaggi matematici, senza necessità di ricalcolarlo da zero; per freshness
si sceglie il timestamp più recente; la lista locations
può essere semplicemente allargata con i nuovi elementi, mentre per description
sarà compito del server decidere se dare la precedenza alle "proprie" descrizioni o adottare politiche differenti.
I campi degli eventi presentati in questo protocollo rappresentano i requisiti minimi che ogni gruppo DEVE garantire. "Garantire" significa che ogni applicazione deve essere in grado di svolgere due operazioni: inviare JSON con ALMENO quei campi e aspettarsi JSON con ALMENO quei campi. Qualsiasi gruppo è libero di estendere il formato aggiungendo campi per la PROPRIA applicazione client/server, ma (naturalmente) non può aspettarsi che i server degli altri ricevano e gestiscano le informazioni aggiuntive. Allo stesso modo, in lato "ricezione", ogni server deve funzionare perfettamente con un client che invia e richiede SOLO i campi minimi.
Questo comporta un impegno particolare nella corretta gestione dei campi "vuoti" o con valori di default (se mi aspetto dal client un campo aggiuntivo "XYZ" e il client non mi invia nulla del genere devo essere in grado di ignorare il campo o di settarlo automaticamente ad un valore standard). Si raccomanda di fare attenzione e di ricordarsi che la parola d'ordine è interoperabilità: aggiungere va bene, togliere o modificare no.