Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

couchbase mobile

1,051 views

Published on

couchbase mobile

  1. 1. Corso Couchbase Lite di Beniamino Ferrari 1 Couchbase Lite per Android
  2. 2. Corso Couchbase Lite di Beniamino Ferrari 2 Data Modeling ● Couchbase è un document database ● Diversamente dai database tradizionali, i dati vengono memorizzati in documenti invece di usare righe di tabelle ● Un documento è un oggetto JSON contenente un certo numero di coppie chiave valore ● Le entità e le relazioni tra di esse sono mantenute all'interno di documenti
  3. 3. Corso Couchbase Lite di Beniamino Ferrari 3 JSON Overview (1) ● JSON, che sta per JavaScript Object Notation, è formato per la rappresentazione di dati: – Leggero – Easily Parsed – Cross-Platform – Ampiamente diffuso in ogni linguaggio, framework e nel Javascript di ogni browser
  4. 4. Corso Couchbase Lite di Beniamino Ferrari 4 JSON Overview (2) ● JSON supporta gli stessi valori e tipe supporati da JavaScript. Questi sono: – Number: un number rappresenta un numero che può essere un tipo intero i decimale a virgola mobile. Javascript supporta un massimo di 2^53. Se vengono utilizzati numeri a 64 bit dovrebbero essere memorizzati come stringhe. – String: una stringa deve essere chiusa fra doppi apici e supportare i caratteri Unicode e i caratteri di escape. Per esempio: "A String"
  5. 5. Corso Couchbase Lite di Beniamino Ferrari 5 JSON Overview (3) – Boolean: un boolean è true o false. Per esempio: { "value": true} – Array: un array è un lista di valori chiusi tra parentesi quadre. Per esempio: ["one", "two", "three"] – Object: un object è un insieme di coppie chiave valore (array associativo o hash). La chiave deve essere una stringa, ma il valore può essere uno qualsiasi dei valori rappresentati in JSON. Per esempio: { "servings" : 4, "subtitle" : "Easy to make in advance, and then cook when ready", "cooktime" : 60, "title" : "Chicken Coriander }
  6. 6. Corso Couchbase Lite di Beniamino Ferrari 6 Da tabelle a JSON (1) ● Il punto di partenza per modellare un database NoSQL è di osservare come viene memorizzata una entity denormalizzata memorizzata in un singolo documento: ID FIRS_NAME LAST_NAME EMAIL 100 John Smith johnsmith@libero.it L'equivalente JSON corrisponde al documento: { "id": “contact100”, “type”:”contact”, "first_name":"John", "last_name ":"Smith", "email": "johnsmith@libero.it" }
  7. 7. Corso Couchbase Lite di Beniamino Ferrari 7 Da tabelle a JSON (2) ● Se volessimo memorizzare una entità con relazione 1 a 1 per es l'indirizzo del contatto potremmo modellare il json nel seguente modo: { "id": “contact100”, “type”:”contact”, "first_name":"John", "last_name ":"Smith", "email": "johnsmith@libero.it", "address": { "address_line": "123 Main Street", "city": "Mountain View", "country": "US" } }
  8. 8. Corso Couchbase Lite di Beniamino Ferrari 8 Relazioni uno a molti ● La cosa diventa interessante quando il nostro contatto possiede più record nella relazione, creando una relazione uno a molti ● Ci sono due modi per modellare una relazione uno a molti in un document database: 1)Embedded Document 2)Related Document
  9. 9. Corso Couchbase Lite di Beniamino Ferrari 9 Embedded Documents (1) ● In un database relazionale, quando un contatto può avere più indirizzi, gli indirizzi vengono comunemente memorizzati una tabella separata (ADRESSES table) ID CONTCT_ID ADDRESS_LINE CITY COUNTRY 200 100 123 Main Street Mountain View US 201 100 123 Market San Francisco US ● In un document database, gli indirizzi potrebbero essere memorizzati in un array di documenti embedded all'interno del contact document ● L'approccio document embedded riduce il lavoro necessario per utilizzare con l'oggetto contact, perché non servono informazioni aggiuntive per risalire alle informazioni embedded
  10. 10. Corso Couchbase Lite di Beniamino Ferrari 10 Embedded Documents (2) { "id": “contact100”, “type”:”contact”, "first_name":"John", "last_name ":"Smith", "email": "john.smith@couchbase.com", "addresses": [ { "address_line": "123 Main Street", "city": "Mountain View", "country": "US" }, { "address_line": "123 Market", "city": "San Francisco", "country": "US" } ] }
  11. 11. Corso Couchbase Lite di Beniamino Ferrari 11 Embedded Documents (1) ● In un database relazionale, quando un contatto può avere più indirizzi, gli indirizzi vengono comunemente memorizzati una tabella separata (ADRESSES table) ID CONTCT_ID ADDRESS_LINE CITY CO§UNTRY 200 100 123 Main Street Mountain View US 201 100 123 Market San Francisco US ● In un document database, gli indirizzi potrebbero essere memorizzati in un array di documenti embedded all'interno del contact document ● L'approccio document embedded riduce il lavoro necessario per utilizzare con l'oggetto contact, perché non servono informazioni aggiuntive per risalire alle informazioni embedded
  12. 12. Corso Couchbase Lite di Beniamino Ferrari 12 Related Documents (1) ● Ci sono scenari in cui l'approccio embedded document non è adatto: – Grande numero di entità nella relazione: inserire un grande numero di entità embendded formerebbe un grande documento. Questo formerebbe un documento più lento da gestire, per via del fatto che dovrebbe essere parsato interamente per eseguire operazioni di aggiornamento. – Concorrenza: quando più utenti lavorano un singolo documento c'è un più alto rischio di conflitti. I Related Document possono essere usati per isolare aggiornamenti eseguiti da utenti differenti
  13. 13. Corso Couchbase Lite di Beniamino Ferrari 13 Related Documents (2) ● Nelle implementazioni più comuni vengono utilizzati per rispondere alla domanda “Appartiene a?”. ● Considerando lo scenario dove ogni utente possa assegnare uno o più “task” a un contatto e un contatto possa arrivare ad avere un grande numero estremamente variabile di “task”. { "id": "task300", “type”:”task” , "contact_id": "contact100" "description": "Task details", "status": "complete" } ● Con questo tipo di implementazione, gli utenti possono modificare record concorrentemente senza introdurre casi di conflitto in record di contatti collegati ● Questo tipo di approccio supporta un grande numero di records per contatto senza impattare alle dimensioni del record del contatto collegato
  14. 14. Corso Couchbase Lite di Beniamino Ferrari 14 Couchbase Lite (1) ● Couchbase Lite è un database JSON embedded che può essere usato in maniera standalone, in una rete P2P o come end point remoto di per un Couchbase Server. ● Rappresenta dati in in maniera flessibile. I dati hanno una rappresentazione libera e i record chiamati documenti possono avere struttura differente. ● Un sofisticato query engine permette di eseguire query in maniera efficiente su data set di grandi dimensioni a prescindere da come sia composta la struttura dei dati. ● Dispone API native per C#, IOS e Android, con le quali è possibile mappare direttamente database a oggetti. ● Le api sono compatibili con Web App che fanno uso di JavaScript o con app ibride.
  15. 15. Corso Couchbase Lite di Beniamino Ferrari 15 Couchbase Lite (2) ● Supporta la replica con database compatibili. Questo predispone la vostra app alla funzionalità di sincronizzazione efficiente. ● Gli utenti possono mantenere la stessa app sincronizzai su diversi device e con gli altri utenti ● Supporta la replica peer-to-peer. Aggiungendo un componente HTTP, la nostra app accetterà connessioni dal altri dispositivi che dispongono di Couchbase Lite e lo scambio di dati con essi ● Supporta accesso a dati offline. In contrasto con le tradizionali applicazioni web tradizionali dove si fa uso spesso di richieste e risposte qui si fa prima accesso ai dati locali. Questo vuol dire che l'applicazione rimarrà responsiva sia in WIFI, che su reti basate su celle oppure offline. Gli utenti potranno modificare i propri dati che mentre sono offline e saranno sincronizzati con il server non appena possibile.
  16. 16. Corso Couchbase Lite di Beniamino Ferrari 16 Api Nativa ● I principali componenti dell'API nativa sono: – Manager – Database – Document – Revision – Attachment – View – Query – Replication
  17. 17. Corso Couchbase Lite di Beniamino Ferrari 17 Manager ● Il Manager è l'oggetto al primo livello che gestisce una collection di istanze di Couchbase lite Database. ● È necessario creare un'istanza della classe Manager prima che sia possibile lavorare con oggetti Couchbase Lite all'interno della nostra applicazione
  18. 18. Corso Couchbase Lite di Beniamino Ferrari 18 Creare un Manager ● Un oggetto Manager può essere creato chiamando un costruttore o l'inizializzatore della classe Manager public class Application extends android.app.Application { private Manager manager; private static Context mContext; @Override public void onCreate() { super.onCreate(); mContext = getApplicationContext(); try { manager = new Manager(new AndroidContext(mContext), Manager.DEFAULT_OPTIONS); } catch (IOException e) { Log.e(TAG, "Cannot create Manager instance", e); return; } } }
  19. 19. Corso Couchbase Lite di Beniamino Ferrari 19 Dove si trova il database ● Il Manager crea una directory nel filesystem e memorizza all'interno di esso il database. Normalmente, non c'è bisogno di sapere dove si trova. ● In Android il percorso di questa cartella è dato dal metodo getFilesDir() dell'oggetto Android Context ● In Android è possibile cambiare il percorso di questa cartella creando una sottoclasse di com.couchbase.lite.Context e un override del metodo getFilesDir
  20. 20. Corso Couchbase Lite di Beniamino Ferrari 20 Manager Options ● Per default il Manager apre il database con accesso lettura/scrittura. Se si vuole assicurare che esso non venga modificato è possibile restringere l'accesso al database in readonly passando un oggetto ManagerOptions al costruttore o inizializzatore di Manager. try { ManagerOptions customOptions = new ManagerOptions(); customOptions.setReadOnly(true); manager = new Manager(new AndroidContext(mContext), customOptions); } catch (IOException e) { Log.e(TAG, "Cannot create Manager instance with custom options", e); return; }
  21. 21. Corso Couchbase Lite di Beniamino Ferrari 21 Supporto della concorrenza ● In Java tutti gli Oggetti Couchbase Lite possono essere condivisi liberamente tra thread.
  22. 22. Corso Couchbase Lite di Beniamino Ferrari 22 Classe Database ● Un Database è sia un contenitore e che un namespace per documenti, lo scope delle query e il target della replica. ● I database sono rappresentati della classe Database ● La maggior parte delle applicazioni hanno bisogno di un solo database, ma è possibile usare il Manager per crearne altri. ● Ogni database è indipendente, l'approccio multi database potrebbe essere preso in considerazione nel caso di un'applicazione multi utente.
  23. 23. Corso Couchbase Lite di Beniamino Ferrari 23 Database ● Un database possiede i seguenti elementi: – Nome: deve consistere di solo lettere lowercase ASCII, cifre, e/o da caratteri speciali _$()+-/ – Documenti: ogni documento è definito univocamente dal suo ID – Views: ogni view ha un nome univoco e un indice persistente – Filter function – Replications
  24. 24. Corso Couchbase Lite di Beniamino Ferrari 24 Document (1) ● In un document database come Couchbase Lite, l'entità memorizzata in un database è chiamato documento invece di “righa” o “record” ● In Couchbase Lite (come in Couchbase Server e CouchDB) il corpo di un documento ha la forma di un oggetto JSON ● Un oggetto JSON è collezione una coppie chiave/calore nella quale i valori possono essere di tipo differente di dati: numeri, stringhe, array o oggetti nidificati
  25. 25. Corso Couchbase Lite di Beniamino Ferrari 25 Document (1) ● In un document database come Couchbase Lite, l'entità memorizzata in un database è chiamato documento invece di “righa” o “record” ● In Couchbase Lite (come in Couchbase Server e CouchDB) il corpo di un documento ha la forma di un oggetto JSON ● Un oggetto JSON è collezione una coppie chiave/calore nella quale i valori possono essere di tipo differente di dati: numeri, stringhe, array o oggetti nidificati
  26. 26. Corso Couchbase Lite di Beniamino Ferrari 26 Document (2) ● Ogni documento è identificato da un document ID, che può essere generato automaticamente come UUID o determinato all'interno dell'applicazione. L'unico vincoli sono che debba essere unico all'interno del database che non possa essere cambiato ● In aggiunta, un documento può contenere allegati binari chiamati blobs che sono utili per contenere file multimediali o altri dati non testuali ● Couchbase Lite supporta gli allegati di dimensioni illimitate, anche se il Gateway di sincronizzazione attualmente impone un limite di 10 MB.
  27. 27. Corso Couchbase Lite di Beniamino Ferrari 27 Document (3) ● Couchbase lite tiene traccia dello storico di ogni documento, come una serie di revisioni ● Funziona come sistema di versioning simile a GIT o Subversion ● Ogni volta che un documento viene creato o aggiornato gli viene assegnato un nuovo e unico revision ID
  28. 28. Corso Couchbase Lite di Beniamino Ferrari 28 Document (4) ● Un documento è composto da i seguenti attributi: – Document ID – Current Version ID che viene aggiornato ad ogni document update – Uno storico delle revisioni passate – Un corpo formato da un Oggetto JSON – Da zero o più allegati
  29. 29. Corso Couchbase Lite di Beniamino Ferrari 29 CRUD di un documento ● Couchbase Lite supporta le tipiche operazioni CRUD su documenti: – Create – Read – Update – Delete.
  30. 30. Corso Couchbase Lite di Beniamino Ferrari 30 Creare Documenti ● È possibile creare un documento assegnando ad esso un ID. Se non è necessario definire un proprio ID chiamando la il metodo createDocument della classe Database l'ID viene generato casualmente nella forma Universally Unique ID (UUID)
  31. 31. Corso Couchbase Lite di Beniamino Ferrari 31 Esempio Creare Documenti (1) ● Map<String, Object> properties = new HashMap<String, Object>(); properties.put("type", "list"); properties.put("title", title); properties.put("created_at", currentTimeString); properties.put("owner", "profile:" + userId); properties.put("members", new ArrayList<String>()); Document document = database.createDocument(); document.putProperties(properties); ● Questo esempio mostra come creare un documento con UUID assegnato automaticamente
  32. 32. Corso Couchbase Lite di Beniamino Ferrari 32 Creazione con ID Assegnato ● Se volessimo creare un nuovo documento e assegnare ad esso un document ID, dovremo: – chiamare il metodo getDocument, come se dovessimo recuperare un documento esistente; – se il documento non esiste ancora otterremo comunque un un oggetto Document valido, esso non avrà nessun contenuto ne revisione; – la prima volta che viene impostato il documento viene memorizzato in maniera persistente nel database; – se esiste un documento con lo stesso ID a database memorizzandolo verrà prodotto un errore;
  33. 33. Corso Couchbase Lite di Beniamino Ferrari 33 Creazione con ID assegnato dal programmatore Map<String, Object> properties = new HashMap<String, Object>(); properties.put("title", "Little, Big"); properties.put("author", "John Crowley"); properties.put("published", 1982); Document document = database.getDocument("978-0061120053"); try { document.putProperties(properties); } catch (CouchbaseLiteException e) { Log.e(TAG, "Cannot save document", e); } ● Questo esempio mostra come creare un documenti assegnandogli un ID ● Questo è l'ideale nei casi in cui esista già un ID univoco come il codice fiscale
  34. 34. Corso Couchbase Lite di Beniamino Ferrari 34 Leggere un Documento ● Per ottenere un Documento dato il suo ID è necessario utilizzare getDocument ● Gli oggetti document sono unici come gli ID dei documenti ● Istanziando due documenti con lo stesso ID si ottiene sempre il riferimento allo stesso oggetto
  35. 35. Corso Couchbase Lite di Beniamino Ferrari 35 Esempio di lettura Document doc = database.getDocument(myDocId); // Possiamo accedere alle proprietà attraverso l'oggetto document: doc.getProperty("title"); // o attraverso le proprietà del suo dizionario Map<String, Object> properties = doc.getProperties(); String owner = (String) properties.get("owner");
  36. 36. Corso Couchbase Lite di Beniamino Ferrari 36 Aggiornare un documento (1) ● Ci sono due metodi per aggiornare un documento: – putProperties – update ● putProperties è più semplice, dato un nuovo oggetto JSON, sostituisce con esso il corpo del documento. Con le proprietà del nuovo oggetto viene creata una nuova revisione che diviene la revisione corrente del documento.
  37. 37. Corso Couchbase Lite di Beniamino Ferrari 37 Esempio di putProperty Document doc = database.getDocument(myDocID); Map<String, Object> properties = new HashMap<String, Object>(); properties.putAll(doc.getProperties()); properties.put("title", title); properties.put("notes", notes); try { doc.putProperties(properties); } catch (CouchbaseLiteException e) { e.printStackTrace(); }
  38. 38. Corso Couchbase Lite di Beniamino Ferrari 38 Aggiornare un documento (2) ● Da notare che multiple update usando putProperties all'interno di una singola transazione non sono supportate. ● L'update è un metodo riceve in ingresso un DocumentUpdater, che possiede un metodo callback (update) che riceve in ingresso della classe UnsavedRevision le quali proprietà sono una copia mutabili delle proprietà correnti. ● La callback può modificare l'oggetto UnsavedRevision come meglio crede
  39. 39. Corso Couchbase Lite di Beniamino Ferrari 39 Esempio di Update Document doc = database.getDocument(myDocId); doc.update(new Document.DocumentUpdater() { @Override public boolean update(UnsavedRevision newRevision) { Map<String, Object> properties = newRevision.getUserProperties(); properties.put("title", title); properties.put("notes", notes); newRevision.setUserProperties(properties); return true; } });
  40. 40. Corso Couchbase Lite di Beniamino Ferrari 40 Conflitti ● In entrambe i modi in cui memorizziamo i cambiamenti, è necessario prendere in considerazione della possibilità di conflitti di aggiornamento ● Couchbase Lite utilizza un Multiversion Concurrency Control (MVCC) a guardia di aggiornamenti simultanei di un documento ● Anche nel caso di un'applicazione single thread esiste un thread replicator che gira in background che potrebbe creare delle revisioni mentre stiamo eseguendo delle modifiche
  41. 41. Corso Couchbase Lite di Beniamino Ferrari 41 Conflitti ● La tipica sequenza che crea conflitti è: 1)il nostro thread legge le proprietà del documento corrente e costruisce una copia modificata che deve essere memorizzata; 2)un altro thread aggiorna il documento, creando una nuova revisione con proprietà differenti; 3)il nostro thread aggiorna il documento con le proprietà modificate; ● Chiaramente se il nostro thread avesse il permesso di procedere i cambiamenti dello step 2 verrebbero sovrascritti e persi. Invece, la modifica fallirà con un conflict error.
  42. 42. Corso Couchbase Lite di Beniamino Ferrari 42 Gestione Conflitti ● Le due modalità hanno un comportamento diverso: – putProperties semplicemente restituisce un errore da gestire. E' necessario intercettare questo tipo di errore e gestirlo ad es. ritentando la modifica – update è più intelligente gestisce autonomamente gli errori di conflitto e ritentando la modifica fino a che non ci sono conflitti ● È raccomandabile usare a seconda, tenendo presente che possa essere chiamata più volte.
  43. 43. Corso Couchbase Lite di Beniamino Ferrari 43 Cancellazione di Documenti ● La cancellazione di un Documento crea un nuova revisione, chiamata tombstone, che possiede la proprietà _delete impostata a true. Questo assicura che l'eliminazione venga replicata sul server e poi su tutti gli altri client che leggono dati dal database Document task = (Document) database.getDocument("task1"); task.delete();
  44. 44. Corso Couchbase Lite di Beniamino Ferrari 44 Preservare proprietà dopo la cancellazione ● Nel caso fosse necessario preservare uno o più campi all'interno di un documento, ad esempio, chi ha eliminato e quando è stato eliminato, sarà necessario modificare il documento e impostare il campo deletion di UnsavedRevision a true Document doc = database.getDocument(myDocId); doc.update(new Document.DocumentUpdater() { @Override public boolean update(UnsavedRevision newRevision) { newRevision.setIsDeletion(true); Map<String, Object> properties = newRevision.getUserProperties(); properties.put("deleted_at", currentTimeString); newRevision.setUserProperties(properties); return true; } })
  45. 45. Corso Couchbase Lite di Beniamino Ferrari 45 Notifiche di modifica a un Documento (1) ● È possibile intercettare gli eventi di modifica o eliminazione di un particolare documento ● Può essere utile per le seguenti motivazioni: – notificare quando una nuova revisione viene aggiunta a un documento; – notificare quando un documento viene eliminato; – notificare quando il documento entra nello stato di conflitto;
  46. 46. Corso Couchbase Lite di Beniamino Ferrari 46 Notifiche di modifica a un Documento (2) Document doc = database.createDocument(); doc.addChangeListener(new Document.ChangeListener() { @Override public void changed(Document.ChangeEvent event) { DocumentChange docChange = event.getChange(); String msg = "New revision added: %s. Conflict: %s"; msg = String.format(msg, docChange.getAddedRevision(), docChange.isConflict()); Log.d(TAG, msg); } }); doc.createRevision().save();
  47. 47. Corso Couchbase Lite di Beniamino Ferrari 47 Purge di un documento ● Eseguire il purge di un documento è differente della eliminazione, il metodo purge rimuove ogni traccia del documento locale, non ha nessun effetto sulla replica nei database remoti ● Purge è un modo per recuperare spazio, ad es. se il eseguo il purge di un documento e successivamente viene modificato su di un server remoto, alla prossima replica il documento verrà ripristinato.
  48. 48. Corso Couchbase Lite di Beniamino Ferrari 48 Proprietà Speciali ● Il corpo di un documento contiene alcune proprietà speciali che contengono metadati – _id: ID del documento. – _rev: ID revisione. – _attachments: metadati degli allegati – _deleted: appare solamente durante una revisione di eliminazione (tombstone) , dove ha valore true. ● Un underscore iniziale denota sempre una proprietà speciale e perciò non dovrebbe essere usato come prefisso
  49. 49. Corso Couchbase Lite di Beniamino Ferrari 49 Revisioni (1) ● Couchbase Lite utilizza le revisioni per risolvere conflitti durante la replica ● Una delle differenze significative rispetto agli altri database è il versioning dei documenti (MVCC Multiversioning Concurrency Control) che gestisce conflitti tra più scrittori ● Ogni documento ha un campo speciale _rev che con contiene ID delle revisione, che viene assegnato ad ogni aggiornamento
  50. 50. Corso Couchbase Lite di Beniamino Ferrari 50 Revisioni (2) ● Quando dobbiamo memorizzare un documento aggiornandone uno esistente, è obbligatorio fornire l'ID della versione corrente. ● Se la versione corrente non coincide con quella effettiva, l'aggiornamento viene interrotto, questo sta indicare che un altri cliente ha fatto una modifica prima. ● Sarà necessario creare una nuova versione e ritentare l'aggiornamento
  51. 51. Corso Couchbase Lite di Beniamino Ferrari 51 Revisioni (3) ● In Couchbase lite non è possibile utilizzare le versioni per memorizzare e recuperare lo storico dei cambiamenti di una pagina, come in un SVN, ma le versioni vengono memorizzate e utilizzate solo per risolvere conflitti ● Le versioni non vengono mai replicate e periodicamente eliminate nel processo di compattazione
  52. 52. Corso Couchbase Lite di Beniamino Ferrari 52 Allegati ● Gli allegati memorizzano dati associati al documento, ma non sono parte dell'oggetto JSON ● Il loro compito principale è quello di rendere efficiente le memorizzazioni di grandi dati binari in un documento ● Un documento può avere zero o più allegati con nome differente e un MIME type ● Rendono la replica efficiente, nel caso un documento possedesse degli allegati solamente quelli che sono stati modificati verranno trasferiti attraverso la rete
  53. 53. Corso Couchbase Lite di Beniamino Ferrari 53 Leggere allegati ● La classe Revision possiede alcuni metodi per accedere agli allegati – attachmentNames restituisce i nomi di tutti gli allegati. – attachmentNamed restituisce un oggetto Attachment dato il nome. – attachments restituisce tutti gli oggetti Attachment. // Carica un allegato JPEG in un Drawable: Document doc = database.getDocument("Robin"); Revision rev = doc.getCurrentRevision(); Attachment att = rev.getAttachment("photo.jpg"); if (att != null) { InputStream is = att.getContent(); Drawable d = Drawable.createFromStream(is, "src name"); }
  54. 54. Corso Couchbase Lite di Beniamino Ferrari 54 Memorizzare un allegato ● Per creare un allegato, è necessario: – creare prima un oggetto UnsavedRevision mutabile, attraverso, il metodo createRevision della versione corrente del documento; – utilizzare il metodo setAttachment sulla nuova revisione per aggiungere il nuove allegato; – e per ultimo, chiamare il metodo save sulla nuova revisione; ● L'aggiornamento funziona esattamente alla stessa maniera chiamando il metodo setAttachment si sostituisce l'allegato mantenendo lo stesso nome
  55. 55. Corso Couchbase Lite di Beniamino Ferrari 55 Es. Aggiunta allegato // Aggiungo un'immagine come allegato dopo che viene invocato la camera activity di Android protected void onActivityResult(int requestCode, int resultCode, Intent data){ InputStream stream = null; if (requestCode == REQUEST_CODE && resultCode == Activity.RESULT_OK) { InputStream stream = getContentResolver().openInputStream(data.getData()); // Aggiungo o aggiorno un'immagine al documento come allegato Document doc = database.getDocument("Robin"); UnsavedRevision newRev = doc.getCurrentRevision().createRevision(); newRev.setAttachment("photo.jpg", "image/jpeg", stream); newRev.save(); } }
  56. 56. Corso Couchbase Lite di Beniamino Ferrari 56 Rimozione di un allegato ● Per la rimozione dell'allegato è necesarrio chiamarre il metodo removeAttachment, invece, di setAttachment // Rimuovo l'allegato dal documento: Document doc = database.getDocument("Robin"); UnsavedRevision newRev = doc.getCurrentRevision().createRevision(); newRev.removeAttachment("photo.jpg");
  57. 57. Corso Couchbase Lite di Beniamino Ferrari 57 Lo storage degli Allegati ● Generalmente, non è necessario pensare come Couchbase Lite memorizzi i dati, ma dato che gli allegati possono occupare molto spazio può essere utile sapere dove e come viegono gestititi ● Gli allegati non sono memorizzati nel database stesso, ma invece in singoli file. ● Ogni allegato ha un nome criptico che corrisponde al digest del contenuto usando SHA1, di conseguenza, vengono deduplicati perché a più nomi uguali corrisponde lo stesso contenuto
  58. 58. Corso Couchbase Lite di Beniamino Ferrari 58 Eliminazione allegati ● Aggiornando o eliminando un allegando un documento non corrisponde ad una immediata eliminazione del file corrispondente ● Il file allegato rimane memorizzato fino a quando esiste una revisione del documento collegato ● Verrà eliminato quando avviene il processo di compattazione dopo che è avvenuta un'operazione di modifica o eliminazione su di esso.
  59. 59. Corso Couchbase Lite di Beniamino Ferrari 59 View (1) ● Una view è un indice persistente all'interno dei documenti del database ● Couchbase Lite non ha un linguaggio per le richieste come SQL, ma usa una tecnica chiamata map/reduce per generare indici (views) secondo un criterio definito all'interno dell'applicazione ● Il principale componente è la sua map function che viene scritta nello stesso linguaggio utilizzato dalla nostra applicazione
  60. 60. Corso Couchbase Lite di Beniamino Ferrari 60 View (2) ● La view genera una qualsiasi numero di coppie chiave/valore che si desidera indicizzare ● Per esempio potrebbe cercare all'interno di un database “rubrica” e produrre un insieme di nomi associati a numeri di telefono ● L'indice ottenuto è persistente e viene aggiornato quando viene aggiornato il documento ● Una view potrà avere una reduce function che può essere usata per combinare più righe in una. Può essere usata per compiere funzioni aggregative come totali, media o raggruppare righe secondo un criterio comune
  61. 61. Corso Couchbase Lite di Beniamino Ferrari 61 Ordinamento dei risultati ● null ● false, true (in questo ordine) ● Numbers, in ordine numerico ● Strings, case-insensitive. In ordine definito dal Unicode Collation Algorithm. ● Arrays, confrontati elemento per elemento come descritto prima. ● Maps/dictionaries, confrontati elemento per elemento come descritto prima. Sfortunatamente l'ordine degli elementi al loro interno è ambiguo (dato che JSON non specifica nessun ordinamento delle chiavi, e nella maggior parte delle implementazioni delle hash table l'ordine delle chiavi è casual) perciò l'uso di queste chiavi è sconsigliato.
  62. 62. Corso Couchbase Lite di Beniamino Ferrari 62 Creare e inizializzare una View ● Un oggetto view appartiene a un Database ● È possibile creare o recuperare chiamando il metodo getView di database, che creerà e restituirà una nuova view se non ne esiste già una ● Nonostante la view sia persistente, la sua map o reduce function non lo sono, non sono nient'altro che metodi vengono registrati a runtime, prima di venire invocati. ● È buona norma impostare le view quando l'applicazione viene avviata dopo l'apertura del database
  63. 63. Corso Couchbase Lite di Beniamino Ferrari 63 Esempio creazione di una View // Creazione di una view e registrazione della sua map function // Questa funzione permette di conoscere il nome della persona dato uno dei suoi numeri di telefono View phoneView = database.getView("phones"); phoneView.setMap(new Mapper() { @Override public void map(Map<String, Object> document, Emitter emitter) { List<String> phones = (List) document.get("phones"); for (String phone : phones) { emitter.emit(phone, document.get("name")); } } }, "2"); ● Il secondo parametro di setMap sta ad indicare la versione, se lo sviluppatore dovesse cambiare il comportamento della map function dovrebbe incrementare il suo valore, in modo tale che al prossimo avvio gli indici vengano rigenerati
  64. 64. Corso Couchbase Lite di Beniamino Ferrari 64 Map Function ● Il compito di una map function è di cercare all'interno del contenuto JSON di un documento e da quello produrre (emit) zero o più coppie chiave/valore che devono essere indicizzate function(doc) { if (doc["type"] == "person") emit(doc["name"], doc["phone"]); } ● Questa funzione JavaScript, agisce in database che contengono documenti rappresentanti persone, che vengono taggati come “person”, usando proprietà type ● L'uso della proprietà type è di uso comune ● La map function semplicemente controlla se il documento rappresenta una “person”, e se vero chiama la emit per aggiungere “name” e “phone” all'indice ● Sarà possibile inoltre richiedere range di nomi o richiederli in ordine alfabetico ● Le map function sono chiamate dagli indexer e devono rispettare determinati requisiti
  65. 65. Corso Couchbase Lite di Beniamino Ferrari 65 Regole da rispettare in map function 1) Devono essere puramente funzioni: questo significa che se chiamate con un certo input devono produrre sempre lo stesso output, non possono usare perciò uno stato esterno ma solamente il JSON in input 2) Non possono avere “effetti collaterali”, non devono cambiare valori all'esterno della funzione, è imprevedibile quando o quanto spesso vengano chiamate 3) Devono essere thread-safe, potrebbero essere chiamate in background da thread indexer o da diversi thread in parallelo
  66. 66. Corso Couchbase Lite di Beniamino Ferrari 66 Chiavi e valori ● Entrambi chiave e valore passati alla emit possono essere di qualsiasi tipo compatibile con oggetti JSON: strings, numbers, booleans, arrays, dichitionary/maps e il JSON null (differente da un null reference). ● I valori prodotti dalla emit possono essere prodotti valori del tipo null reference, ma non per le chiavi ● Le chiavi sono comunemente stringhe, ma ci sono casi in cui può essere comodo averli come array ad es. quando si vuole ottenere un ordinamento multilivello. ● Se la emit della map function avesse per chiave [lastname, firstname] otterremmo l'equivalente di ORDER BY lastname, firstname
  67. 67. Corso Couchbase Lite di Beniamino Ferrari 67 Simulare Join ● Eseguire Join SQL di documenti non è possibile all'interno di View ● La Join SQL può essere simulata facendo uso del campo usato per il link.
  68. 68. Corso Couchbase Lite di Beniamino Ferrari 68 Esempio simulazione Join (1) ● Considerando due record delle tabelle 'post' e 'comment': ● post con _id 1000 { "type" : "post", "title" : "Blog post" "author" : "Blog author" } comment con _id 1002 { "type" : "comment", "post_id" : "post_1000" "author" : "Comment author", "created_at" : 123498235 }
  69. 69. Corso Couchbase Lite di Beniamino Ferrari 69 Esempio simulazione Join (2) ● Creare una view che mostri i post di un blog e tutti records collegati è ottenibile con la seguente map function: function(doc, meta) { if (doc.post_id && doc.type && doc.type == "post") { emit([doc.post_id, null], null); } else if (doc.post_id && doc.created_at && doc.type && doc.type == "comment") { emit([doc.post_id, doc.created_at], null); } }
  70. 70. Corso Couchbase Lite di Beniamino Ferrari 70 Reduce function ● Un reduce function post processa le coppie chiave/valore indicizzate dalla map function, aggregandone i valori ● Le reduce function sono simili agli operatori di aggregazione COUNT o AVERAGE dell'SQL, solo che il programmatore ha l'onere di definirli ● Un reduce function prende in ingresso una lista ordinata di coppie chiave/valore, aggregandola in un singolo oggetto che viene restituito da essa
  71. 71. Corso Couchbase Lite di Beniamino Ferrari 71 Esempio di reduce function // Creo una view e reigstro la sua map e reduce function View phoneView = database.getView("phones"); phoneView.setMapReduce(new Mapper() { @Override public void map(Map<String, Object> document, Emitter emitter) { List<String> phones = (List) document.get("phones"); for (String phone : phones) { emitter.emit(phone, document.get("name")); } } }, new Reducer() { @Override public Object reduce(List<Object> keys, List<Object> values, boolean rereduce) { return new Integer(values.size()); } }, "2"); ● Il corpo di questa reduce function stampa il numero totale di tutti i numeri di telefono presenti in rubrica
  72. 72. Corso Couchbase Lite di Beniamino Ferrari 72 Rereducing ● Il parametro rereduce serve a indicare la reduce function deve essere chiamata in modalità re-reduce ● In modalità re-reduce non ci sono chiavi e valori contenuti nel db, ma i valori sono sostituiti con i risultati delle chiamate delle reduce function svolte in precedenza ● Questo permette all'indexer di non utilizzare a una view composta da centinaia di milioni di righe, che porterebbe la nostra applicazione crash, ma di utilizzare solamente i risultati ottenuti in precedenza
  73. 73. Corso Couchbase Lite di Beniamino Ferrari 73 Rereducing Javascript function(key, values, rereduce) { var result = {total: 0, count: 0}; for(i=0; i < values.length; i++) { if(rereduce) { result.total = result.total + values[i].total; result.count = result.count + values[i].count; } else { result.total = sum(values); result.count = values.length; } } return(result); }
  74. 74. Corso Couchbase Lite di Beniamino Ferrari 74 Rereducing Android // Creo una view e reigstro la sua map e reduce function con parametro rereduce View phoneView = database.getView("phones"); phoneView.setMapReduce(new Mapper() { @Override public void map(Map<String, Object> document, Emitter emitter) { List<String> phones = (List) document.get("phones"); for (String phone : phones) { emitter.emit(phone, document.get("name")); } } }, new Reducer() { @Override public Object reduce(List<Object> keys, List<Object> values, boolean rereduce) { if (rereduce) { return View.totalValues(values); } else { return new Integer(values.size()); } } }, "2");
  75. 75. Corso Couchbase Lite di Beniamino Ferrari 75 Regole per la reduce function ● La reduce function ha le stesse restrizioni della map function: dev'essere puramente una funzione che produce sempre lo stesso output dato un input. Non deve avere side effect ed essere thread safe. In aggiunta: – Se il suo output, dovesse essere composto da un array o un dizionario, allora, dovrà essere composto da meno elementi del suo input. Se accadesse il contrario la nostra applicazione potrebbe andare in crash per carenza di memoria
  76. 76. Corso Couchbase Lite di Beniamino Ferrari 76 Query ● Una query è la ricerca di risultati dato l'indice di una view. ● Couchbase Lite le query sono oggetti della classe Query ● Per eseguire una query è necessario creare un oggetto della Classe query e personalizzarne gli attributi come range e massimo numero di righe e poi eseguirla ● Il risultato è contenuto in un oggetto di tipo QueryEnumerator, che dispone di una lista di oggetti QueryRow ciascuno dei quali descrive una riga attraverso indice di una view
  77. 77. Corso Couchbase Lite di Beniamino Ferrari 77 All-docs e live query ● All-doc query non è associata a nessuna view, con questo tipo di query si può immaginare di interrogare una view che contiene una riga per ogni documento contenuto nel database. Queste vengono utili per conoscere dati comuni a tutti i documenti come ad es. i documenti in conflitto ● Live query una volta create rimangono attive e monitorano i cambiamenti agli indici delle view, notificando agli observer quando i risultati della query sono cambiati. Live query sono molto utili per gestire componenti UI come tabelle.
  78. 78. Corso Couchbase Lite di Beniamino Ferrari 78 Creare e Configurare Query ● Gli oggetti query sono creati chiamando il metodo createQuery su di una view e dal metodo createAllDocumentsQuery della classe Database ● Ci sono diverse proprietà che si possono configurare per gestire le query, ma le più importanti e comuni sono: – startKey: la chiave iniziale, per default null che significa iniziare dalla prima – endkey: l'ultima chiave da restituire, per default null che significa arrivare fino alla fine – desceding: se true le chiavi vengono restituite nell'ordine inverso – limit: se diverso da zero indica il numero di righe da restituire – skip: se diverso da zero indica il numero di righe che devono essere saltate
  79. 79. Corso Couchbase Lite di Beniamino Ferrari 79 Proprietà avanzate delle query (1) ● Altre proprietà avanzate – Keys: impostando questa proprietà (una lista di chiavi) verranno restituite solo le righe associate alle chiavi contenute in essa (startkey e endkey saranno ignorate) – StartKeyDocID: se più chiavi corrispondano alla startKey è possibile impostare la prima tramite ID – EndKeyDocID: se più chiavi corrispondano alla endKey è possibile impostare l'ultima tramite ID – IndexUpdateMode: cambia il comportamento dell'indicizzazione, per default l'indice verrà aggiornato se necessario prima di eseguire la query. È possibile saltare l'indicizzazione con diverse modalità
  80. 80. Corso Couchbase Lite di Beniamino Ferrari 80 Proprietà avanzate delle query (2) ● Ci sono altri proprietà avanzate che personalizzano il grouping e il reducing – MapOnly: se impostata a true non la reduce function non verrà eseguita – GroupLevel: se maggiore di zero, abilità il raggruppamento di righe. Il valore indica il numero di elementi che verranno raggruppati (equivale a GROUP BY).
  81. 81. Corso Couchbase Lite di Beniamino Ferrari 81 Esempio di una query ● Imposto una query per una view che indiciazza i post di un blog e ottenendo gli ultimi 20 Query query = database.getView("postsByDate").createQuery( ); query.setDescending(true); query.setLimit(20);
  82. 82. Corso Couchbase Lite di Beniamino Ferrari 82 All-documents query ● All-doc query non sono associate a una view ● Supportano tutte le opzioni standard delle Query, come creare range e invertire ordine ● Le query All-docs hanno delle proprietà speciali per personalizzare il loro comportamento: – allDocs: modalità di default che ritorna tutti i documenti non eliminati – IncludeDeleted: include i documenti eliminati – ShowConflicts: in questa modalità ogni oggetto QueryRow può essere usato per sapere è in conflitto e quali sono gli ID delle revisioni in conflitto – OnlyConflicts: si comporta come showConflicts ma vengono restituiti solo i documenti in conflitto
  83. 83. Corso Couchbase Lite di Beniamino Ferrari 83 es. di all- docs query // Trovo tutti i documenti i conflitto Query query = database.createAllDocumentsQuery(); query.setAllDocsMode(Query.AllDocsMode.ONLY_CONFLICTS); QueryEnumerator result = query.run(); for (Iterator<QueryRow> it = result; it.hasNext(); ) { QueryRow row = it.next(); if (row.getConflictingRevisions().size() > 0) { Log.w("MYAPP", "Conflict in document: %s", row.getDocumentId()); } }
  84. 84. Corso Couchbase Lite di Beniamino Ferrari 84 Eseguire Query ● Una volta impostato un oggetto delle classe Query è sufficiente chiamare il metodo run che restituirà i risultati dell'interrogazione ● I risultati sono contenuti in un oggetto che fa da contenitore QueryEnumerator che servirà per ottenere un collection di oggetti QueryRow ● Ogni QueryRow ha due proprietà che contengono chiave e valore, che corrispondono a quelle che vengono inserite nell'indice tramite emit ● In una QueryRow contiene inoltre il documentID del documento da dove sono stati presi chiave e valore
  85. 85. Corso Couchbase Lite di Beniamino Ferrari 85 Esempio di interrogazione // Interrogo una view che mappa nomi prodotto in prezzi, // che partono dalla chiave "m" fino a 100 prodotti: Query query = database.getView("widgetsByName").createQuery(); query.setStartKey("m"); query.setLimit(100); QueryEnumerator result = query.run(); for (Iterator<QueryRow> it = result; it.hasNext(); ) { QueryRow row = it.next(); Log.w("MYAPP", "Widget named %s costs $%f", row.getKey(), ((Double)row.getValue()).doubleValue()); }
  86. 86. Corso Couchbase Lite di Beniamino Ferrari 86 Aggiornare query ● Se volessimo aggiornare ciclicamente il risultato della query potremmo controllare la proprietà stale ● Se stale è false indica che la view non è cambiata ed eseguendo nuovamente la query otterremo gli stessi risultati ● Se stale è true significa che gli indici sono cambiati ma le righe potrebbero essere le stesse. Per evitare di aggiornare dati quando non c'è ne bisogno basterà confrontare l'oggetto QueryEnumerator ottenuto con l'attuale usando il metodo equals
  87. 87. Corso Couchbase Lite di Beniamino Ferrari 87 Esempio di verifica che i dati siano cambiati // Verifica che dati della query siano cambiati: if (queryResult == null || queryResult.isStale()) { QueryEnumerator newResult = query.run(); if (!queryResult.equals(newResult)) { queryResult = newResult; updateMyUserInterface(); } }
  88. 88. Corso Couchbase Lite di Beniamino Ferrari 88 LiveQuery ● Una live query rimane attiva e monitora il database e indici delle view in attesa di cambiamenti. ● Quando c'è un cambiamento si esegue nuovamente in autonomia e notifica gli observer ● LiveQuery è un metodo intelligente per creare interfacce utente reattive, specialmente per tabelle o liste che si aggiornino ad ogni cambiamento del database
  89. 89. Corso Couchbase Lite di Beniamino Ferrari 89 Esempio di live query private void initializeQuery() { // Set up my live query during view initialization: Query query = database.getView("widgets").createQuery(); query.setLimit(100); LiveQuery liveQuery = query.toLiveQuery(); this.liveQuery = liveQuery; liveQuery.addChangeListener(new LiveQuery.ChangeListener() { @Override public void changed(LiveQuery.ChangeEvent event) { if (event.getSource().equals(this.liveQuery)) { this.displayRows(event.getRows()); } } }); this.liveQuery.start(); }
  90. 90. Corso Couchbase Lite di Beniamino Ferrari 90 Reducing ● Se la view ha una reduce function, viene chiama per default quando viene chiamata la una query della view. ● Questo significa che tutte le righe in output saranno aggregate in una singola riga senza chiave, il quale valore corrisponde all'output della reduce function ● Secondo il l'ordinamento di default l'output della reduce function è contenuto nella prima riga
  91. 91. Corso Couchbase Lite di Beniamino Ferrari 91 Esempio di reducing // In questa view chiavi sono le date degli ordini, e i valori sono i prezzi. // La reduce function è la media dei valori. Query query = database.getView("ordersByDateView").createQuery(); query.setStartKey("2014-01-01"); query.setEndKey("2014-02-01"); // Eseguo la query senza reduce function e mostro gli ordini del Gennaio 2014: query.setMapOnly(true); QueryEnumerator result = query.run(); for (Iterator<QueryRow> it = result; it.hasNext(); ) { QueryRow row = it.next(); Log.w("MYAPP", "On %s: order for $%f", row.getKey(), ((Double)row.getValue()).doubleValue()); } // Eseguo la query senza reduce function per ottenere la media dei prezzi di Gennaio 2014: query.setMapOnly(false); QueryEnumerator result = query.run(); QueryRow aggregate = result.next(); Log.w("MYAPP", "Average order was $%f", ((Double)aggregate.getValue()).doubleValue());
  92. 92. Corso Couchbase Lite di Beniamino Ferrari 92 Raggruppamento per chiave ● La proprietà groupLevel permette di collassare righe avente stessa chiave o stessa lista di chiavi prefisso ● La reduce function può essere usata per ottenere statistiche sulle righe raggruppate ● Quando il groupLevel va da 2 a N, la query raggruppa i valore dei primi N elementi degli array chiave creando una singola riga con chiave l'array composto dal prefisso di n elementi ● Quando groupLevel è 1 supporta le chiavi che non sono array ● I valori di ogni riga sarà il risultato della reduce function
  93. 93. Corso Couchbase Lite di Beniamino Ferrari 93 Esempio di Grouping (1) ● Dato un database libreria musicale, contenente per ogni traccia una riga ● Creiamo un view con chiave l'array [genre, artist, album, trackname] e valore durata della traccia in secondi. Questa view ha reduce function la somma degli ingressi ● Vogliamo creare una lista degli album di genere “MopeRock” dei “Radiohead” e la lista delle durate.
  94. 94. Corso Couchbase Lite di Beniamino Ferrari 94 Esempio di Grouping (2) Query query = database.getView("hierarchyView").createQuery(); query.setGroupLevel(3); query.setStartKey(Arrays.asList("Mope-Rock", "Radiohead")); query.setEndKey(Arrays.asList("Mope-Rock", "Radiohead", new HashMap<String, Object>())); // groupLevel=3 restituirà l'array con contenente le chiavi [genre, artist, album] . List<String> albumTitles = new ArrayList<String>(); List<String> albumTimes = new ArrayList<String>(); QueryEnumerator result = query.run(); for (Iterator<QueryRow> it = result; it.hasNext(); ) { QueryRow row = it.next(); List<String> key = (List) row.getKey(); albumTitles.add(key.get(2)); // titolo è il 3° elemento della chiave albumTimes.add((String)row.getValue()); // il valore è la durata dell'album }
  95. 95. Corso Couchbase Lite di Beniamino Ferrari 95 Replica ● La replica o sincronizzazione viene eseguita tramite un oggetto di classe Replication, che trasferisce cambiamenti da un database locale a uno remoto ● Per eseguire una replica, è necessario ottenere un oggetto Replication da un oggetto Database, configurarne alcuni parametri e avviarne l'esecuzione ● La replica viene eseguita in background da un thread asincrono ● È possibile monitorare il progresso controllando le notifiche generate dall'oggetto Replication ad ogni suo cambiamento di stato, oppure, utilizzando e notifiche generate dal database quando i documenti vengono modificato dal replicator
  96. 96. Corso Couchbase Lite di Beniamino Ferrari 96 Pull e Push ● Una tipica applicazione crea due di repliche pull e push, entrambe puntano all'URL del server ● Queste rimangono attive per tutto il cliclo di vita dell'applicazione, caricando e scaricando documenti ad ogni cambiamento e quando la rete è disponibile ● Il codice dell'applicazione non dovrebbe fare attenzione al replicator, ma conoscere solamente che i documenti modificati verranno inviati al server e che i cambiamenti sul server verranno scaricati sul server locale
  97. 97. Corso Couchbase Lite di Beniamino Ferrari 97 Tipi di Replica ● Pull – Push: una replica push carica cambiamenti da un database locale a uno remoto; una replica pull scarica modifiche da database remoto a uno locale ● One-shot – Continua: da default, una replica continua fino a quando tutti cambiamenti sono stati trasferiti da sorgente a destinazione. Un replica continua, rimane attiva indefinitivamente, controllando e scaricando le nuove modifiche. ● Filtered: la replica può avere dei filtri che restringono quali documenti inclusi nel trasferimento. Questo può essere utile per limitare il numero di documenti che vengono scaricati sul device o per mantenerne una parte privata
  98. 98. Corso Couchbase Lite di Beniamino Ferrari 98 Creare e configurare le repliche ● È possibile creare un oggetto Replication utilizzando il metodo createPullReplication o il metodo createPushReplication di un oggetto Database. Entrambi accettano come parametro l'url del database remoto su cui eseguire la sincronizzazione ● Una volta creato un oggetto Replication è possibile customizzare la property continuos a true o ad es il tipo di autnticazione
  99. 99. Corso Couchbase Lite di Beniamino Ferrari 99 Esempio di creazione di Replica URL url = new URL("https://example.com/mydatabase/"); Replication push = database.createPushReplication(url); Replication pull = database.createPullReplication(url); pull.setContinuous(true); push.setContinuous(true); Authenticator auth = new BasicAuthenticator(username, password); push.setAuthenticator(auth); pull.setAuthenticator(auth);
  100. 100. Corso Couchbase Lite di Beniamino Ferrari 100 Iniziare una replica ● Inoltre, è possibile monitorare il progresso della sincronizzazione per mostrare l'avanzamento all'utente o mostrare eventuali errori ● Una volta che tutto è impostato andrà chiamato il metodo start per avviare la replica, che terminerà quando tutte le modifiche saranno trasferiti, mentre se continua continuerà perpetuamente.
  101. 101. Corso Couchbase Lite di Beniamino Ferrari 101 Esempio di avvio di una replica push.addChangeListener(new Replication.ChangeListener() { @Override public void changed(Replication.ChangeEvent event) { // verrà chiamato quando cambia lo stato della replica in push } }); pull.addChangeListener(new Replication.ChangeListener() { @Override public void changed(Replication.ChangeEvent event) { // verrà chiamato quando cambia lo stato della replica in pull } }); push.start(); pull.start(); this.push = push; this.pull = pull;
  102. 102. Corso Couchbase Lite di Beniamino Ferrari 102 Filtrare repliche in push ● Durante la replica in push il documento candidato risiede localmente, perciò la filter function verrà eseguita localmente. ● Il programmatore dovrà definirla in linguaggio nativo, assegnarle un nome e registrarla all'interno dell'oggetto Database ● Il replicator passerà al nostro filtro un oggetto SavedRevision, e attraverso di esso sarà possibile accettare o rifiutare il documento, restituendo true o false rispettivamente.
  103. 103. Corso Couchbase Lite di Beniamino Ferrari 103 Esempio di Filtro in push // Definisco un filtro che lascia passare solo i documenti con determinato "owner" . // Il parametro da controllare è quello con chiave “name” db.setFilter("byOwner", new ReplicationFilter() { @Override public boolean filter(SavedRevision revision, Map<String, Object> params) { String nameParam = (String) params.get("name"); return nameParam != null && nameParam.equals(revision.getProperty("owner")); } }); // Imposto una replica filtrata in push che usa la precedente filter fuction, // così invieremo in push solo i documenti che hanno "owner" uguale a "Pippo": Replication push = db.createPushReplication(url); push.setFilter("byOwner"); Map<String, Object> params = new HashMap<String, Object>(); params.put("name", "Pippo"); push.setFilterParams(params);
  104. 104. Corso Couchbase Lite di Beniamino Ferrari 104 Filtrare replica in pull da un Sync Gateway ● Sistema che viene utilizzato per filtrare documenti in pull è quello dei Canali ● Ogni documento che viene memorizzato nel Sync Gateway viene taggato con un insieme di canali, attraverso una funzione app-defined risiedente sul gateway (sync function) ● Ogni replica in pull da un Gateway è implicitamente filtrata da un set di canali che corrispondono ai documenti a cui un utente ha il permesso permesso accedere ● È possibile creare un filtro in pull aggiuntivo creando un array di canali che ci permetterà di ottenere tutti i documenti etichettati con i canali contenuti in esso.
  105. 105. Corso Couchbase Lite di Beniamino Ferrari 105 Esempio di filtro in pull usando un Sync Gateway // Imposto una replica in pull filtrata in modo da // ottenere solo i documenti etichettati come // “sales” dal Sync Gateway: db.createPullReplication(url); List<String> channels = new ArrayList<String>(); channels.add("sales"); pull.setChannels(channels);

×