Synchroniza£ní modul pro Mozilla Thunderbird - ExtBrain

Transkript

Synchroniza£ní modul pro Mozilla Thunderbird - ExtBrain
České vysoké učení technické v Praze
Fakulta elektrotechnická
Katedra počítačů
Diplomová práce
Synchronizační modul pro Mozilla Thunderbird
Bc. David Kalivoda
Vedoucí práce: Ing. Tomáš Novotný
Studijní program: Elektrotechnika a informatika, strukturovaný,
Navazující magisterský
Obor: Výpočetní technika
květen 2012
iv
v
Prohlášení
Prohlašuji, že jsem práci vypracoval samostatně a použil jsem pouze podklady uvedené
v přiloženém seznamu.
Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000
Sb., o právu autorském, o právech souvisejících s právem autorským a o změně některých
zákonů (autorský zákon).
Ve Starém Hradišti dne 1. 5. 2012
.............................................................
vi
Abstract
Content of this thesis is designing and implementing information synchronization module
for Mozilla Thunderbird over remote storage as IMAP server. Besides common branches of
software engineering, thesis deals with universal principles of synchronization and versioning. There is ExtBrain Sync Protocol which takes control of the synchronization process
described in this thesis.
Abstrakt
Náplní této práce je návrh a implementace synchronizačního modulu informací pro Mozilla
Thunderbird přes vzdálené úložiště v podobě IMAP serveru. Práce se kromě obvyklých
disciplín softwarového inženýrství zabývá obecnými principy synchronizace a verzováním
informací. V práci je popsán obecný ExtBrain Sync Protokol, podle kterého synchronizace
probíhá.
vii
viii
Obsah
1 Úvod
1.1 Motivace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Struktura práce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1
1
2 Popis problému, specifikace
2.1 Popis problému . . . . . .
2.2 Specifikace cíle . . . . . .
2.3 Zadání projektu . . . . . .
2.4 Rešerše existujících řešení
.
.
.
.
3
3
3
3
4
cíle
. . .
. . .
. . .
. . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3 Analýza a návrh implementace
3.1 Analýza . . . . . . . . . . . . . . . . . . . . . . .
3.1.1 Specifikace požadavků . . . . . . . . . . .
3.1.2 Princip synchronizace . . . . . . . . . . .
3.1.3 Vzdálené úložiště - IMAP protokol . . . .
3.1.4 GUI Thunderbirdu s ohledem na kontakty
3.1.5 Mozilla Application Framework . . . . . .
3.2 Návrh implementace . . . . . . . . . . . . . . . .
3.2.1 Struktura aplikace . . . . . . . . . . . . .
3.2.2 Řešení kolizí . . . . . . . . . . . . . . . .
3.2.3 Formát přenášených objektů . . . . . . .
3.2.4 Optimalita datového přenosu . . . . . . .
3.2.5 Rozšíření atributů kontaktů . . . . . . . .
3.2.6 Použité nástroje . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9
9
9
9
12
15
15
16
16
18
18
18
19
20
4 ExtBrain Sync Protokol
4.1 Definice pojmů . . . . . . . . . . . . . .
4.2 Označení položky . . . . . . . . . . . . .
4.3 Lokální a databázové úložiště . . . . . .
4.4 Vzdálené úložiště . . . . . . . . . . . . .
4.5 Fáze synchronizace . . . . . . . . . . . .
4.6 Fáze import . . . . . . . . . . . . . . . .
4.6.1 Získání UIDNEXT a EXISTS . .
4.6.2 Načtení hlaviček IMAP zpráv . .
4.6.3 Načtení těl a příloh nových zpráv
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
23
23
23
24
24
24
25
26
27
28
ix
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
x
OBSAH
4.7
4.8
4.9
Synchronizační jádro . . . . . . . . . . . .
4.7.1 Vytvoření synchronizační tabulky .
4.7.2 Procházení synchronizační tabulky
Fáze export . . . . . . . . . . . . . . . . .
4.8.1 Krok zápisu . . . . . . . . . . . . .
4.8.2 Krok přesouvání . . . . . . . . . .
Paralelní přístup . . . . . . . . . . . . . .
4.9.1 Zamykání vzdáleného úložiště . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5 Realizace
5.1 Obecný synchronizační modul . . . . . . . . . . . . . . . .
5.1.1 Průběh volání v jednotlivých fázích synchronizace
5.2 Databázové úložiště . . . . . . . . . . . . . . . . . . . . .
5.3 Obsluha IMAP úložiště . . . . . . . . . . . . . . . . . . .
5.3.1 Posloupnost IMAP příkazů . . . . . . . . . . . . .
5.3.2 Struktura obsluhy volání IMAP příkazu . . . . . .
5.3.3 Zamykání vzdáleného úložiště . . . . . . . . . . . .
5.3.4 IMAP knihovna . . . . . . . . . . . . . . . . . . .
5.4 Synchronizační modul kontaktů . . . . . . . . . . . . . . .
5.4.1 Implementace . . . . . . . . . . . . . . . . . . . . .
5.4.2 Definice formátu obsahu přenášených zpráv . . . .
5.4.3 Serializace a deserializace kontaktů . . . . . . . . .
5.4.4 Chyba v jádru Thunderbirdu . . . . . . . . . . . .
5.4.5 Řešení kolizních situací . . . . . . . . . . . . . . .
5.5 Grafické uživatelské rozhraní . . . . . . . . . . . . . . . .
5.5.1 Rozšíření atributů kontaktu . . . . . . . . . . . . .
5.5.2 Wizard na tvorbu účtů . . . . . . . . . . . . . . . .
5.5.3 Obsluha synchronizace . . . . . . . . . . . . . . . .
6 Testování
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
28
29
31
36
37
38
39
39
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
41
41
41
43
44
44
45
46
47
47
47
47
48
48
50
50
50
50
51
53
7 Závěr
55
7.1 Možná další rozšíření . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Literatura
57
A Seznam použitých zkratek
59
B Obrázky a diagramy
61
C Instalační příručka
67
C.1 Instalace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
C.2 Vytvoření účtu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
C.3 Spuštění synchronizace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
D Obsah přiloženého CD
71
Seznam obrázků
2.1
2.2
2.3
Okno se zobrazením průběhu synchronizace (SyncKolab) . . . . . . . . . . . .
Kolizní okno doplňku SyncKolab . . . . . . . . . . . . . . . . . . . . . . . . .
Rozšíření položek v kontaktech v doplňku gContactSync . . . . . . . . . . . .
3.1
3.2
3.3
Grafické rozhraní editace kontaktu v Thunderbirdu 11.0.1 . . . . . . . . . . . 15
Návrh třívrstvé architektury . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Návrh okna pro řešení kolizních situací . . . . . . . . . . . . . . . . . . . . . . 18
4.1
4.2
4.3
4.4
4.5
4.6
Fáze procesu synchronizace . . . . . . . . . . . . . . .
Stavový diagram fáze import . . . . . . . . . . . . . .
Stavový diagram jádra synchronizace . . . . . . . . . .
Poslední podmínka průchodu synchronizační tabulkou
Stavový diagram fáze export . . . . . . . . . . . . . .
Stavový diagram zamykání vzdáleného úložiště . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
26
29
32
36
40
5.1
5.2
5.3
5.4
5.5
5.6
Class diagram synchronizačního modulu . . . . .
Sekvenční diagram fáze import . . . . . . . . . .
Sekvenční diagram fáze export . . . . . . . . . .
Relační databázový model . . . . . . . . . . . . .
Okno pro editaci kontaktů s rozšířenými atributy
Okno informující o průběhu synchronizace . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
42
43
43
44
51
52
B.1
B.2
B.3
B.4
B.5
Návrh okna pro editaci kontaktů . . . . . .
Sekvenční diagram všech fází synchronizace
Volání IMAP příkazů v initialSequence . . .
Volání IMAP příkazů v importSequence . .
Volání IMAP příkazů v exportSequence . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
61
62
63
64
65
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
4
5
7
C.1 Úvodní okno průvodce pro vytváření účtů . . . . . . . . . . . . . . . . . . . . 68
C.2 Okno se seznamem složek na serveru . . . . . . . . . . . . . . . . . . . . . . . 68
C.3 Spuštění synchronizace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
xi
xii
SEZNAM OBRÁZKŮ
Seznam tabulek
3.1
3.2
Tabulka synchronizace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Trojcestné slučování - příklad . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.1
4.2
4.3
4.4
4.5
4.6
Načtení hlaviček IMAP zpráv . . . . . . . .
Načtení těl IMAP zpráv . . . . . . . . . . .
Synchronizační tabulka - příklad . . . . . .
Možné situace v synchronizační tabulce . .
Příklad struktury objektu objectsToExport
Příklad struktury objektu objectsToDelete .
5.1
JSON atributy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
27
29
30
31
35
35
B.1 Kontakt v JSON podobě . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
xiii
xiv
SEZNAM TABULEK
Kapitola 1
Úvod
1.1
Motivace
Při současném trendu velkého rozvoje chytrých telefonů a dalších jiných mobilních zařízení je
kladen velký důraz jednak na zabezpečení takových zařízení, ale také na přenášení souborů,
kontaktů, záložek a dalších informací, které je výhodné mít ve stejných verzích na všech
zařízeních. Při více než dvou používaných zařízeních pro služby jako volání, psaní e-mailů
atd. již nestačí synchronizovat tato zařízení pouze mezi sebou, ale při dodržení obvyklých
bezpečnostních pravidel je lepší využívat centrální úložiště, na kterém jsou data uchovávána. Pomocí klientských aplikací na jednotlivých zařízeních jsou na toto centrální úložiště
data odesílána, při synchronizačním procesu data z úložiště získávána, při výskytu kolizních
situací musí aplikace zajistit její vyřešení. Nejde jen o to přesunovat soubory a informace
z jednoho zařízení na druhé, nýbrž je přenášet obousměrně, pokud možno v reálném čase
a po každé změně na jedné ze stran. Tento trend se velmi přibližuje modelu využívání IT
technologií zvaný jako „cloud computing“. V každém případě může služby „v cloudu“ velmi
dobře doplňovat.
Pro přiblížení motivace pro tuto práci můžeme vzít běžnou konkrétní situaci: máme
mobilní telefon s kontakty a na jiném zařízení e-mailového klienta. V tomto případě je
samozřejmě účinné mít na všech zařízeních kontakty sdílené tak, abychom v případě změny
např. e-mailu u jednoho kontaktu editaci nemuseli provádět několikrát. Změníme-li kontakt
na jednom zařízení, chceme, aby se kontakt v této verzi uložil „někam na server“, odkud si
jeho změny na jiném zařízení nahrajeme.
Cílem této práce je návrh a implementace aplikace, která bude umožňovat synchronizaci informací v e-mailovém klientu Mozilla Thunderbird přímo v jeho prostředí, bude se
jednat o zásuvný modul. Řešení poskytující synchronizaci například kontaktních údajů již
samozřejmě existují, žádné z nich ovšem není nijak obecné a většinou nesplňují požadavky
na dlouhodobé bezproblémové nasazení.
1.2
Struktura práce
V následující kapitole se zaměřím na konkrétní popis cílů práce a podrobný rozbor existujících řešení. Díky inspiraci a poučení se z nedostatků konkurence v kapitole Analýza a
1
2
KAPITOLA 1. ÚVOD
návrh popíšu jaké konkrétní postupy jsem se rozhodl zvolit. Zaměřím se zde i na obecné
principy synchronizace. V kapitole ExtBrain Sync Protokol bude místo pro podrobný popis
protokolu, podle kterého se synchronizace řídí. Pomocí stavových diagramů a konkrétního
příkladu provázejícího celou tuto kapitolu bude vysvětlen flow dat při synchronizaci. Kapitola Realizace se bude týkat konkrétních tříd výsledné implementace. Kapitola Testování
bude věnována popisu testů, které byly na implementovanou aplikaci provedeny. V závěru
se pokusím shrnout výsledek projektu s ohledem na zadání diplomové práce, praktickou
použitelnost a nastínit možnosti budoucích rozšíření.
Kapitola 2
Popis problému, specifikace cíle
2.1
Popis problému
E-mailový klient Mozilla Thunderbird, tak jak je to u podobných aplikací běžné, obsahuje
adresář s kontakty. Vstup kontaktů do adresáře je možný přes ruční zadávání v grafickém
uživatelském rozhraní, nebo přes funkci import. Ta ve verzi Thunderbird 11.0 podporuje
následující formáty: vCard, LDIF, textové formáty s daty oddělenými tabelátorem nebo
čárkou (.csv) a přímý import adresářových souborů z aplikací Outlook, Outlook Express a
Eudora.
V jádru aplikace chybí možnost synchronizace či uložení na sdílené úložiště. Synchronizací se zabývá několik doplňků Thunderbirdu (jejich seznam a stručná rešerše je uvedena
dále v této kapitole). Tyto doplňky synchronizují kontakty z adresáře do složky na lokálním
úložišti, několik z nich podporuje synchronizaci se službou Google Contacts a některé umožňují jako vzdálené úložiště zvolit IMAP server. Toto je užitečné například pro korporátní
uživatele, kde s ohledem na bezpečnost chceme využít například firemní IMAP server.
Užitečnost synchronizace v e-mailovém klientu se však netýká pouze kontaktů, ale i
událostí v kalendáři, nebo například poznámek k e-mailovým zprávám.
2.2
Specifikace cíle
Cílem této práce je návrh a implementace zásuvného modulu do Mozilla Thunderbird rozšiřujícího jej o možnosti synchronizace informací pomocí IMAP protokolu. S využitím tohoto
modulu bude pak implementováno rozšíření pro synchronizaci kontaktů. Atributy kontaktů
v Mozilla Thunderbird budou rozšířeny na formát odpovídající atributům v OS Android.
Zásuvný modul bude napsán v jazyce JavaScript obvyklém pro implementaci rozšíření Thunderbirdu.
2.3
Zadání projektu
Diplomová práce byla zadána v rámci projektu ExtBrain [1], který se zaměřuje na vývoj
aplikací usnadňujících každodenní práci na PC. Projekt ExtBrain již zahrnuje některé aplikace pro Mozilla Application Framework, například e-mailového klienta a IM komunikátor.
3
4
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE
Synchronizační modul bude po dokončení integrován do většího celku sdružujícího všechna
ExtBrain rozšíření pro Mozilla Thunderbird.
2.4
Rešerše existujících řešení
V následujících odstavcích jsou shrnuty výsledky zkoušení několika zásuvných modulů do
Thunderbirdu včetně heslovitého zhodnocení kladných a záporných vlastností, které tyto
moduly vykazují.
2.4.1
SyncKolab
Obrázek 2.1: Okno se zobrazením průběhu synchronizace (SyncKolab)
Doplněk Thunderbirdu přináší synchronizaci kontaktů přes IMAP server. Ke každé složce
kontaktů, kterou chce uživatel synchronizovat, musí v rozšíření vytvořit samostatný účet.
Verze kontaktů jsou ukládány lokálně ve formátu xml nebo vcard v adresáři profilu, tyto
soubory jsou při synchronizaci přílohou zprávy na serveru, stejně jako fotky, pokud jsou
ke kontaktu přiřazeny. Při smazání fotky v jiném profilu nedojde ke smazání souboru s
fotkou v aktuálním profilu. Fotky jsou uloženy ve složce profilu ve Photos. Autor píše, že na
verzi Thunderbird 3 by měl uživatel používat noční sestavení, ani s ním však v době psaní
2.4. REŠERŠE EXISTUJÍCÍCH ŘEŠENÍ
5
této práce nefunguje GUI umožňující výběr verze při kolizi. Dialog upozorňující na kolizi se
uživateli zobrazí (viz obr. 2.2), tlačítka označující, zda uživatel chce zachovat lokální verzi,
nebo verzi ze serveru, však nereagují. Především ale chybí zobrazení kolidujících položek.
Jedinou možností je tedy zvolit Skip, což vyvolá přeskočení této kolize a kontakt tak není v
konzistentním stavu. SyncKolab nijak nerozšiřuje položky kontaktů, hodí se tak pro použití
mezi více klienty používajícími pouze Thunderbird. Nezotaví se při změně názvu adresáře
(addressBook v Thunderbirdu je uložen jako název, ne URI). Všechny informace o účtech
jsou uloženy v preferencích v about:config.
Synchronizované kontakty: jakékoli
Úložiště: IMAP server, složka v profilu a TH
Fotky: ano
Kolize: ano, ale nefunkční GUI
+
+
+
−
více složek k synchronizaci
použití jakéhokoli IMAP serveru
podpora fotek
nefungující podpora kolizních situací
Obrázek 2.2: Kolizní okno doplňku SyncKolab
2.4.2
Zindus
Doplněk Thunderbirdu přináší synchronizaci kontaktů s Google kontakty nebo Zimbra Server (open-source server pro Linux a Mac umožňující správu e-mailů, kontaktů a kalendářů
[2]). Možnost synchronizace pouze kontaktů v účtu Google (ne libovolné kontakty do složky
na IMAP serveru). Podpora Google Groups v kontaktech. Zindus nijak nerozšiřuje položky
kontaktů. Synchronizace probíhá pouze na úrovni vybraných položek (např. adresa není
zahrnuta vůbec). V doplňku neexistuje okno s kolizemi, bez uživatelova potvrzení přepisuje verzi na serveru lokálními změnami. Nemá žádné interní úložiště pro verze kontaktů.
Nepodporuje mail listy ani fotky.
6
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE
Synchronizované kontakty: google contacts
Úložiště: pouze server a TH
Fotky: ne
Kolize: ne
−
−
−
2.4.3
synchronizace pouze kontaktů v účtu Google
chybí podpora kolizních situací (serverová verze je při kolizi přepsána lokální)
nepodporuje fotky u kontaktů
ThunderSync
Doplněk Thunderbirdu přináší synchronizaci přes úložiště na lokálním disku ve formě vCard
souborů. Lze synchronizovat jakýkoli adresář v Thunderbirdu, pro každý je možné zvolit
složku na disku, do které budou soubory zapisovány. Soubory jsou zapisovány jako vCard 2.1.
ThunderSync nijak nerozšiřuje položky kontaktů, hodí se tak pro použití mezi více klienty
používajícími pouze Thunderbird. Všechny informace o účtech jsou uloženy v preferencích
v about:config. Zotaví se ze změny názvu adresáře v Thunderbirdu, addressBook je uložen
jako URI, ne jako jeho název. Podporuje fotky, ty jsou uloženy přímo ve vCard souboru
jako base64. Při kolizi není žádná verze původní, pouze aktuální z adresáře a vzdálená ze
souboru.
Synchronizované kontakty: jakékoli
Úložiště: pouze složka a TH
Fotky: ano
Kolize: ano
+
+
−
2.4.4
synchronizace jakéhokoli adresáře
podpora fotek
úložiště pouze na lokálním disku
Google Contacts
Doplněk Thunderbirdu umožňuje synchronizaci s Google kontakty. Podporovány jsou tak
pouze kontakty v účtu Google. Synchronizaci nelze ručně vyvolat, lze pouze zvolit, zda
zahájovat synchronizaci při startu Thunderbirdu. Změny v kontaktech jsou pak zapisovány
na server ihned po uložení změny v kontaktu, nekontroluje se ale jejich změna na serveru.
Verze na serveru je vždy přepsána lokální. Podporuje fotky u kontaktů, lokálně je ukládá
do adresáře GoogleContacts/Photos v profilu.
Synchronizované kontakty: google contacts
Úložiště: pouze server a TH
Fotky: ano
Kolize: ne (vždy přepis serverové verze)
+
−
−
podpora fotek
synchronizace pouze kontaktů v účtu Google
chybí podpora kolizních situací (serverová verze je při kolizi přepsána lokální)
2.4. REŠERŠE EXISTUJÍCÍCH ŘEŠENÍ
7
Obrázek 2.3: Rozšíření položek v kontaktech v doplňku gContactSync
2.4.5
gContactSync
Doplněk Thunderbirdu umožňuje synchronizaci s Google kontakty. Lze vytvořit více účtů,
každý však bude spolupracovat pouze s Google kontakty. Toto lze tedy prakticky použít
pouze v situaci, máme-li více Google účtů. Složky s kontakty v Thunderbirdu pak budou
odpovídat kontaktům uloženým v jednotlivých účtech. Neobsahuje okno na řešení kolizí,
směr přepisu při konfliktu uživatel volí v nastavení předem. Podporuje fotky, jsou uloženy ve
standardním adresáři pro fotky v Thunderbirdu (ProfD/Photos). Doplněk rozšiřuje položky
kontaktů tak, aby bylo možné je pohodlně namapovat na základní položky použité v Google
kontaktech (viz obr. 2.3). Zotaví se ze změny názvu adresáře v Thunderbirdu, addressBook
je uložen jako URI, ne jako jeho název.
Synchronizované kontakty: google contacts
Úložiště: google server, soubor se zálohou v profilu a TH
Fotky: ano
Kolize: ne (směr přepisu lze měnit v nastavení rozšíření)
+
−
−
2.4.6
podpora fotek
synchronizace pouze kontaktů v účtu Google
chybí podpora kolizních situací
Addressbook Synchronizer
V průběhu implementační fáze se objevilo ještě jedno rozšíření Thunderbirdu s názvem Addressbook Synchronizer. Podle popisu umožňuje synchronizovat kontakty přes lokální
adresář, FTP, WebDAV a IMAP server. Při testování jsem však došel k závěru, že synchronizace zde není úplná a funkční. Program je založen na výměně souborů ukládaných do
8
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE
jednotlivých úložišť (složka v případě lokálního disku, FTP a WebDAVu, příloha e-mailu
v případě IMAP serveru). Soubory však nereprezentují jednotlivé kontakty, nýbrž jsou to
soubory s příponou .mab obsahující celý adresář. Ačkoli nastavení programu se zmiňuje o
možnostech nastavení chování při kolizích, vždy dochází pouze k přepisu celého adresáře
buď ve vzdáleném úložišti, nebo v Thunderbirdu. Pro práci s takovým rozšířením bychom
museli pečlivě dbát na rozlišování akcí, které vyvoláme. Upload striktně přepíše vzdálenou
verzi, download přepíše lokální změny.
Kapitola 3
Analýza a návrh implementace
3.1
3.1.1
Analýza
Specifikace požadavků
Soustředím se na vytvoření aplikace, která bude vykazovat následující vlastnosti:
∙ obecný synchronizační modul bude mít charakter knihovny,
∙ synchronizovány budou nejen textové položky, ale také přílohy v binárním formátu,
∙ při synchronizaci se budou kompletně řešit kolizní situace,
∙ obecný synchronizační modul bude využit pro implementaci synchronizace kontaktů,
∙ položky kontaktů v Thunderbirdu budou rozšířeny tak, aby lépe odpovídaly kontaktům
ve službě Gmail a v OS Android,
∙ položky budou ukládány každá zvlášť (jedna položka = jeden soubor/e-mail),
∙ synchronizace bude podporovat všechny běžně dostupné IMAP servery,
∙ synchronizace bude co nejoptimálnější ohledně datového přenosu,
∙ aplikace bude podporovat více adresářů a synchronizaci na více IMAP serverech.
3.1.2
Princip synchronizace
Synchronizací je pro účel této práce myšlena jednorázová akce vyvolaná uživatelem či automaticky vedoucí k dosažení stavu, kdy si obsahem a strukturou odpovídají data v lokálním
adresáři a ve vzdáleném úložišti. Na straně lokálního adresáře synchronizaci obsluhuje klientská aplikace, vzdálené úložiště je obsluhováno serverem. Za položky považujeme jednotlivé
entity nacházející se v adresáři, mohou jimi být soubory nebo např. kontakty. Položky jsou
tvořeny z atributů.
9
10
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
3.1.2.1
Základní princip
Základní princip synchronizace lze vysvětlit jednoduchým způsobem:
1. zjistíme, jaké změny jsou ve vzdáleném úložišti (rozhodně se nechceme zabývat srovnáváním všech položek, pokud nenastala žádná změna),
2. zjistíme, k jakým změnám došlo v lokálním adresáři od poslední synchronizace,
3. ze změněných položek si vytvoříme tabulku, kde jeden sloupec označuje lokální změny,
druhý změny ve vzdáleném adresáři, tuto tabulku řádek po řádku procházíme,
4. je-li změna na lokální straně, přepíšeme verzi ve vzdáleném úložišti a naopak.
3.1.2.2
Kolizní situace
Problém nastává v situaci, kdy se v jednom řádku tabulky vyskytuje hodnota v obou sloupcích. V takové chvíli nejsme schopni jednoduše určit, která verze má být upřednostněna.
Tuto situaci lze označit jako kolizní. Kolize tedy nastává v případě, že se klientská aplikace
snaží do vzdáleného úložiště vložit změněnou verzi položky z lokálního adresáře, odpovídající položka na vzdáleném úložišti však byla od předchozí sychronizace změněna. (Tato
změna musela být provedena jinou klientskou aplikací.)
Aby se předešlo takovýmto kolizím v případě současných změn na obou stranách, je
možné na klientské straně synchronizaci podporovat databází, sloužící k uložení předchozích
verzí dat. V tomto ohledu se pak synchronizace podobá procesu verzování, kdy se ukládá
historie provedených změn nad daty tak, aby bylo možné rozpoznat, kdy byla jaká verze
vytvořena. Díky tomu lze například poznat novější verzi a tu při synchronizaci automaticky upřednostňovat. I přesto ale mohou nastávat situace, kdy není aplikace sama schopna
rozhodnout, která verze dat by měla být ponechána. Za pomoci znalosti předchozích změn
při synchronizaci tedy klientská aplikace vyřeší některé situace sama, na některé vyžaduje
zásah uživatele a jeho rozhodnutí. Při verzování změn do synchronizační tabulky přibude
jeden sloupec s označením jako původní (databázová) verze. Verzování změn nad daty má
ještě jednu výhodu, změny lze využít jako zálohu.
V případě verzovacích systémů, které se v současné době používají především na podporu
vývoje softwaru při verzování zdrojových kódu, ke kolizím dochází v případě, že například
více vývojářů mění na svých lokálních počítačích jeden soubor zdrojového kódu, který poté
odešlou do repozitáře1 . Verzovací nástroje v tomto případě většinou nabízí možnost sloučení
souboru, což je proces, při kterém se řádky z jednotlivých verzí zdrojových souborů vkládají
za sebe, až vytvoří jeden výsledný. Slučování (merge) probíhá částečně automaticky, ale
vyžaduje rozhodnutí uživatele v případě nesrovnalostí.
Při rešerši existujících synchronizačních aplikací jsem se často setkal s přístupem, že
kolize jsou řešeny sice automaticky, ale podle předem daného scénáře, např. tak, že je vždy
přepsána lokální verze verzí ze vzdáleného úložiště.
1
ve verzovacích nástrojích se vzdálené úložiště nazývá obvykle repozitář
3.1. ANALÝZA
3.1.2.3
11
Identifikátory
Položky jsou od sebe odlišovány pomocí unikátního atributu označeného jako UUID (beremeli v úvahu např. možnou změnu jména a příjmení u kontaktu je UUID nezbytností), jejich
konkrétní verze jsou pak označovány atributem RevId (celé číslo). RevId v průběhu života
položky roste o 1 s každou změnou. Pomocí dvojice RevId a UUID jsme schopni naplnit
tabulku synchronizace, rychle skrze ní procházet a rozhodovat o akcích, které mají být vykonány.
3.1.2.4
Příklad procházení synchronizační tabulkou
Ukázka toho, jak může synchronizační tabulka vypadat včetně akcí, které je nutné při synchronizaci vykonat, je v tabulce 3.1. Protože není nutné vždy porovnávat přímo hodnoty
položek, ale pouze jejich čísla revizí, jsou v tabulce uvedena pouze tato čísla.
UUID
53
54
55
58
60
62
67
68
71
83
local
3
1
20
15
15
32
1
RevId
remote
2
2
28
15
20
1
3
10
database
2
1
20
14
14
10
32
akce
zápis lokální verze do vzdáleného úložiště
přepis lokální verze vzdálenou
přepis lokální verze vzdálenou
kolize
kolize
vytvoření nové položky v lokálním adresáři
vytvoření nové položky v lokálním adresáři
smazání položky ve vzdáleném úložišti
smazání položky v lokálním adresáři
nová lokální položka, zápis do vzdáleného úl.
Tabulka 3.1: Tabulka synchronizace
Ve chvíli vyvolání synchronizace je každá lokální položka v jednom ze stavů:
buď je identická s verzí v databázi (pak local.RevId==database.RevId),
nebo je změněná a její RevId je oproti databázovému o 1 vyšší.
RevId vzdálené verze se může od RevId lokální verze lišit o libovolné celé číslo, nesmí ale
být menší než RevId v databázi. Je-li vzdálené RevId vyšší než lokální o 2 a více, položka
byla v době od poslední synchronizace několikrát změněna jiným klientem. Tuto situaci
ukazují položky s UUID 55 a 60. První vyvolá přepis lokální verze, druhá vyvolá kolizi
(všimněme si, že lokální položka je oproti databázi změněna).
Zápis verze do databáze je realizován při každém zápisu/přepisu do vzdáleného nebo
lokálního úložiště. Absence RevId je považována za absenci položky s daným UUID v daném
úložišti. Tak je možné pro položku s UUID 71 rozhodnout, že byla ve vzdáleném úložišti
smazána a odstranit ji i lokálně. Není-li UUID nalezeno v databázi ani ve vzdáleném úložišti,
12
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
je to známka toho, že položka byla nově vytvořena – položka s UUID 83. Položky s UUID
62 a 67 naopak existují pouze ve vzdáleném úložišti a budou synchronizovány stažením do
lokálního adresáře.
Z tabulky lze také pozorovat, že číslo RevId z lokálního adresáře a z databáze se liší vždy
maximálně o 1. Je to dáno tím, že číslo verze se zvyšuje jen při vyvolání synchronizace, ne
při každé editaci položky a jejím uložení.
3.1.2.5
Trojcestné slučování
Změnu položky (souboru, kontaktu) v lokálním adresáři poznáme buď pomocí příznaku
označujícího čas poslední změny, nebo přímým porovnáním obsahu položky s poslední verzí
v databázi. Nejsou-li shodné, uživatel položku změnil a měla by tedy být označena vyšším
RevId a následně distribuována na vzdálené úložiště a do databáze. Pokud se ve vzdáleném
úložišti mezitím objevila položka s vyšším RevId, než tím, které máme pro položku naposledy registrované v databázi, nastává kolize. Díky verzování jsme schopni uživateli zobrazit
tabulku s jednotlivými atributy položky a nabídnout předpokládané vyřešení. Kolize se tak
může řešit tzv. trojcestným slučováním (3-way merge), kde jedna verze je lokální, druhá
vzdálená a třetí z databáze (lze označit jako původní). Slučování se neprovádí nad celou položkou jako nedělitelnou množinou, nýbrž nad jednotlivými atributy, ze kterých se výsledná
položka složí. Výsledná verze položky tak může obsahovat jednotlivé atributy pocházející
každý z jiné verze.
Ukázka trojcestného slučování je v tabulce 3.2. Je-li lokální a vzdálená verze stejná,
řešení je snadné, výsledkem bude jedna z těchto verzí. Jsou-li jakékoli jiné dvě verze shodné,
výsledkem je verze třetí. Nerovnají-li se hodnoty žádné dvojice odpovídajících atributů je
o vyřešení této kolize nutné požádat uživatele. V tabulce jsou zvýrazněny vždy dvojice
shodných hodnot atributů. Případ shodnosti celé trojice hodnot (jméno, příjmení) je při
slučování vyhodnocen jako shoda lokální a vzdálené verze.
atribute
jméno
příjmení
telefon
zaměstnání
web
bydliště
local
Karel
Poláček
504-111
reportér
www.polacek.cz
Praha
remote
Karel
Poláček
504-222
reportér
www.ln.cz
Hradec Králové
database
Karel
Poláček
504-111
spisovatel
www.ln.cz
Rychnov n. Kněžnou
result
Karel
Poláček
504-222
reportér
www.polacek.cz
???
Tabulka 3.2: Trojcestné slučování - příklad
Algoritmus slučování je možné v pseudo kódu napsat způsobem viz algoritmus 3.1.
Kvalitní článek zabývající se trojcestným slučováním a algoritmem diff3, který je jeho
implementací, byl vydán na University of Pennsylvania ve spolupráci s Yahoo [3].
3.1.3
Vzdálené úložiště - IMAP protokol
IMAP (Internet Message Access Protocol) je protokol umožňující vzdálený přístup k elektronickým zprávám na serveru a manipulaci s nimi (publikováno v RFC 3501[4]). Protokol
3.1. ANALÝZA
13
Algoritmus 3.1 trojcestné slučování
for all atribute in item do
if ( local.atribute == remote.atribute ) then
result.atribute = local.atribute;
continue;
end if
if ( local.atribute == database.atribute ) then
result.atribute = remote.atribute;
continue;
end if
if ( remote.atribute == database.atribute ) then
result.atribute = local.atribute;
continue;
end if
result.atribute = askUser(atribute);
◁ kolize nemůže být automaticky vyřešena
end for
pracuje na klasickém modelu klient-server, klient odesílá příkazy serveru, který na ně reaguje a odpovídá. Protokol neslouží k odesílání e-mailů (jako SMTP), odchozí zprávy tak
nebudou e-maily v pravém slova smyslu. Odchozí zprávy od klienta na server jsou pouze
uloženy do e-mailové schránky, odkud mohou být později staženy jiným klientem.
Většina dnešních běžně dostupných serverů vyžaduje zabezpečení komunikace, nejčastěji
SSL. Jelikož se jednotlivé servery v přesných implementacích liší, budeme při vývoji brát za
důležitou funkčnost na serveru imap.gmail.com, imap.aol.com a imap.feld.cvut.cz.
3.1.3.1
IMAP zprávy
Protokol byl vytvořen kompatibilní s RFC 822 [5], které definuje strukturu internetových
textových zpráv. V tomto RFC je popsána zpráva jako text členěný na jednotlivé řádky
složený z hlavičky a nepovinně těla zprávy [6] . Tyto části jsou od sebe odděleny prázdným řádkem. Každá položka hlavičky musí začínat na novém řádku a doporučení umožňuje
přidávat i hlavičky vlastní. Toho bude využito pro uchování UUID jednotlivých kontaktů.
Příklad zprávy včetně standardních hlaviček:
1
2
3
4
5
6
7
8
9
MIME-Version: 1.0
Received: by 10.112.23.8 with HTTP; Wed, 4 Feb 2012 14:14:07 -0800 (PDT)
Date: Wed, 4 Feb 2012 23:14:07 +0100
Delivered-To: [email protected]
Message-ID: <[email protected]>
Subject: Greeting
From: Imap Imap <[email protected]>
To: Imap Imap <[email protected]>
Content-Type: text/plain; charset=UTF-8
10
11
Hello Mike!
14
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
Obsah zpráv včetně hlaviček smí obsahovat pouze ASCII znaky, pro přenos znaků mimo
ASCII je tedy nutné znaky převést například pomocí quoted printable, což je způsob přenosu
8 bitových znaků přes 7 bitový kanál. Souhrnně se rozšířením elektronických zpráv o znaky
mimo ASCII zabývá technologie Multipurpose Internet Mail Extensions (MIME) popsaná
v RFC 2045 a 2046. Quoted printable je jedním z možných způsobů tohoto rozšíření.
Ke zprávám je možné přikládat přílohy zakódované ve formátu base64 (taktéž součástí
standardu MIME) toho bude využito pro synchronizaci fotek, které jsou součástí kontaktů.
3.1.3.2
Přidělování RevId
Pro ukládání zpráv na server budeme používat složku v existující e-mailové schránce. Dle
definice protokolu je každé zprávě na serveru přiřazen jednoznačný číselný identifikátor UID
o délce 32 bitů. Protokol zaručuje, že žádná jiná zpráva v dané složce nebude mít UID se
stejnou hodnotou. Při vložení zprávy na server je přiřazen identifikátor (číslo) vyšší, než
předchozí zprávě. Tato vlastnost přesně odpovídá potřebám pro verzování položek, přiřazení atributu RevId jednotlivým verzím. Položky nebudou sice moci se svým RevId začínat
na 1, jako je tomu v tabulce 3.1, odpadne však starost o udržování konzistentního stavu
RevId. Každá položka ve vzdáleném úložišti tedy bude identifikována buď pomocí UUID
(identifikátor položky) nebo RevId (UID zprávy dle IMAP protokolu, identifikátor verze).
V obou případech jednoznačně.
3.1.3.3
IMAP příkazy
Protokol IMAP v základní verzi obsahuje na 20 příkazů, klíčovými pro přenos zpráv jsou:
FETCH – pro načtení zpráv ze složky na serveru. Podporuje celou řadu parametrů pro
získání konkrétních částí zpráv (bude využito pro minimalizaci přenesených dat).
APPEND – pro uložení zprávy do složky na server. Zprávě je po uložení přiřazeno jednoznačné UID, které bude využito na verzování kontaktů (viz dále).
Všechny příkazy pro manipulaci se zprávami na serveru vyžadují parametr identifikující
zprávu nebo sekvenci zpráv. Tímto parametrem je standardně pořadí zprávy ve složce; toto
pořadí se logicky při odstranění zprávy mění. Druhou možností, kterou IMAP příkazy podporují, je identifikace zprávy pomocí UID. Toto UID zůstává po celou dobu existence zprávy
v dané složce neměnné. (RFC definuje ještě atribut UID validity, které připouští možnost
změny UID, zpráva by tak měla být identifikována dvojicí UID a UID validity. Kromě situace, kdy dojde k přetečení UID a reorganizace identifikátorů zpráv je tak nezbytná, však
běžně dostupné servery UID validity nemění.)
Protože verze položek budou nést unikátní UID zpráv, musí být složka na IMAP serveru
po celou dobu vyhrazena pouze pro synchronizování jednoho lokálního adresáře (ke složce
samozřejmě přistupují klienti z různých zařízení, není však možné dovolit, aby byly do jedné
složky vkládány položky z více lokálních adresářů jednoho klienta, případně aby se do složky
ukládaly jiné zprávy než synchronizační).
3.1. ANALÝZA
3.1.3.4
15
Přesouvání starých verzí položek
Vlastností IMAP protokolu je i nemožnost zprávy na serveru editovat. Podporováno je pouze
jejich ukládání, odstranění, případně přesunutí. Změny v kontaktech tedy budeme ukládat
tak, že původní zpráva se smaže a do složky na server bude odeslána zpráva s novou verzí.
Tato zpráva získá unikátní UID, které se pro naše potřeby stane RevId. Pro uchovávání
historie je možné místo odstraňování starých zpráv přesouvání do složky např. Deleted.
Tuto složku bude uživatel moci později kdykoli vymazat.
3.1.4
GUI Thunderbirdu s ohledem na kontakty
Grafické rozhraní pro editaci kontaktů v programu Thunderbird je ukázáno na obrázku 3.1.
Protože součástí práce je rozšíření struktury kontaktů o další položky (atributy kontaktu),
je nutné upravit také toto rozhraní. Přidáné atributy se budou nejvíce týkat typování stávajících atributů (např. přidání možnosti specifikovat typ telefonu – mobilní, pracovní, domů
atd.). Jako inspirace v tomto ohledu poslouží grafické rozhraní zásuvného modulu gContactSync (viz obr. 2.3). Návrh takového okna je na obrázku B.1 v příloze tohoto dokumentu.
Obrázek 3.1: Grafické rozhraní editace kontaktu v Thunderbirdu 11.0.1
3.1.5
Mozilla Application Framework
Zásuvné moduly pro Mozilla Thunderbird stejně jako pro Mozilla Firefox mohou být vyvíjeny v prostředí Mozilla Application Framework. Tento framework postkytuje vývojářům
několik služeb pro jednodušší implementaci. Logika aplikace je psána v jazyce Javascript,
16
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
pro tvorbu grafického uživatelského rozhraní se využívá XUL technologie, je zde i možnost
využití cross-platformních objektových komponent přes technologii XPCOM. K Frameworku
existuje poměrně bohatá dokumentace, ač často se vztahuje již ke starším verzím. Je jí tedy
nutné brát často s rezervou a všechny implementační detaily ověřovat v nových verzích. Při
vývoji byla využita obecná příručka vývoje aplikací pro Mozilla Framework [7], článek o
vývoji zásuvných modulů do Mozilla a Thunderbird aplikací [8] a dále pak dokumentace z
oficiálních stránek pro podporu vývoje [9].
3.2
Návrh implementace
Pro pochopení následujícího návrhu architektury aplikace si dovolím odkázat nejprve na
následující kapitolu 4 věnovanou výhradně podrobnému popisu synchronizačního protokolu.
3.2.1
Struktura aplikace
Aplikace se bude skládat z následujících prvků: obecný synchronizační modul, rozšiřující
modul pro synchronizaci kontaktů, IMAP klient pro komunikaci se vzdáleným úložištěm a
grafické uživatelské rozhraní pro podporu rozšířených atributů kontaktů a tvorbu synchronizačních účtů.
3.2.1.1
Vrstvy synchronizačního modulu
Obecný synchronizační modul je navržen ve třech vrstvách, kde nejnižší vrstva (remote storage) obstarává komunikaci se vzdáleným úložištěm (získávání a ukládání zpráv), prostřední
vrstva (common sync) řídí synchronizační fáze a horní vrstva (items) slouží pro obsluhu položek v lokálním úložišti. Tyto vrstvy jsou naznačeny také v obrázku 3.2.
Obrázek 3.2: Návrh třívrstvé architektury
3.2. NÁVRH IMPLEMENTACE
3.2.1.2
17
Význam a úkoly jednotlivých vrstev
Horní vrstva je od obecné synchronizace oddělena, protože každý typ synchronizovaných
položek vyžaduje jiný přístup. Kontakty v e-mailovém klientu jsou uloženy jinde a za pomocí jiných objektů než události z kalendáře. Obecná obsluha synchronizace však na těchto
podrobnostech ohledně konkrétních položek nesmí záležet. Spodní vrstva je obecné synchronizace oddělena proto, abychom umožnili synchronizačnímu modulu jednoduše přidat i jiné
vzdálené úložiště než jen IMAP server.
Po vrstvě items je vyžadováno umožňovat načítání položek z lokálního úložiště (tvorba
synchronizační tabulky), manipulaci s položkami (jejich vytváření, editaci a odstraňování),
dále serializaci a deserializaci položek do zpráv. Pro různé druhy položek budou sloužit vždy
samostatné třídy vykazující zmiňované funkcionality. Po remote storage vrstvě se vyžaduje,
aby uměla procházet vzdálené úložiště, získávat z něj a zapisovat do něho zprávy (fáze
import, export a zamykání úložiště).
3.2.1.3
Implementace vrstev
Vstupní bod synchronizace bude v horní vrstvě. Voláme vždy synchronizaci konkrétního typu
položek (konkrétního adresáře s kontakty atd.). Z této vrstvy se bude volat třída implementující vrstvu obecné synchronizace, která bude již dále řídit jednotlivé fáze synchronizace.
Vrstva items bude implementována pro různé druhy položek samostatnými třídami. Metody, které musí tyto třídy implementovat, budou popsány dále. V aplikaci k synchronizaci
kontaktů bude konkrétně implementována třídou ContactSynchronization. Vrstva common sync bude implementována pomocí třídy CommonSync. Instance této třídy bude obsahovat objekty jako ukazatele na instance tříd implementujících nadřazenou a podřazenou
vrstvu, přes tyto objekty bude docházet k volání obslužných metod synchronizace. Vrstva
remote storage bude implementována pomocí třídy ImapSyncController s IMAP klientem
a třídy ImapSync, která tohoto klienta obsluhuje.
3.2.1.4
IMAP klient
Klient bude přes socket komunikovat se serverem, starat se o načtení aktuálních verzí položek, zápis nových verzí, přesouvání a odstraňování starých verzí. Při vývoji bude použita a
rozšířena IMAP knihovna Bc. Petra Macha, kterou implementoval v rámci bakalářské práce.
Protože IMAP knihovna je asynchronní, bude celý modul implementován jako flow mezi
metodami jednotlivých tříd. Objekty budou tedy pomocí scope vědět o objektech jejich
metodách, které mají po ukončení svého běhu volat. Přes scope se například do obsluhy
IMAP úložiště dostane odkaz na metodu, která se má zavolat po úspěšném načtení zpráv.
3.2.1.5
Zodpovědnost vrstev v jednotlivých fázích synchronizace
Za importní a exportní fázi je zodpovědná vrstva remote storage. Tato vrstva taktéž zodpovídá za bezchybné zamykání a odemykání vzdáleného úložiště. Odpovědnost za fázi synchronizačního jádra je rozdělena mezi zbývající dvě vrstvy. Common sync má na starost
pouze obecnou synchronizaci a to procházení synchronizační tabulky a verzování položek do
databáze. Pro vytvoření synchronizační tabulky a editaci položek vyžaduje funkce vrstvy
items.
18
3.2.2
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
Řešení kolizí
Aby uživatel mohl při kolizi pohodlně vybírat hodnoty položek, je navrženo zobrazování
těchto kolizí v samostatném okně aplikace. V okně budou v tabulce srovnány hodnoty
jednotlivých subatributů. Existuje-li rovnost alespoň ve dvou hodnotách, je do sloupce s
výsledkem rovnou předvybrána hodnota dle algoritmu slučování, takové řádky jsou pak
podbarveny zeleně. Neexistuje-li řešení podle algoritmu slučování, řádky jsou podbarveny
červeně. Návrh takového okna je v obrázku 3.3.
Obrázek 3.3: Návrh okna pro řešení kolizních situací
3.2.3
Formát přenášených objektů
Pro synchronizaci s ostatními klienty je nutné vytvořit jednotný formát přenášených zpráv
(serializovaných kontaktů). Po dohodě s vedoucím práce jsem se inspiroval projektem Portable Contacts [11], který modeluje kontakty jako JSON elementy [12]. Toto bude pro serializaci kontaktů velmi výhodné, protože mezi JSONy a objekty v Javascriptu je přímý vztah
– lze je mezi sebou nativně převádět. Serializace a deserializace kontaktů je tak elegantně
vyřešena.
3.2.4
Optimalita datového přenosu
Pro dosažení minimálního datového přenosu při synchronizaci bude každý klient ukládat
stav vzdáleného úložiště po každé sychronizaci. Jedná se o dvojici existingItems a nextUID,
3.2. NÁVRH IMPLEMENTACE
19
tedy počet uložených zpráv a UID příští zprávy. Díky znalosti této dvojice můžeme lehce
předejít stahování objemných dat v případě, že se ve vzdáleném úložišti neprovedla žádná
změna. Pokud byla v době od poslední synchronizace nějaká položka ze vzdáleného úložiště odstraněna, musíme sáhnout ke stahování zpráv, abychom zjistili, o kterou položku
se jednalo. I tak je však cílem nestahovat verze položek celé, nýbrž jen jejich hlavičky. Pro
tento účel bude v hlavičce každé zprávy uloženo UUID sloužící k identifikaci kontaktů. Porovnáním stažených UUID z hlaviček s lokální verzí adresáře jednoduše zjistíme například,
který kontakt byl smazán. Teprve při zjištění, že na serveru se nachází nová verze položky
se přistoupí načtení jejího obsahu a přílohy.
3.2.5
Rozšíření atributů kontaktů
Následující odstavce se týkají návrhu rozšíření kontaktů o typy používané v OS Android.
Tento návrh je rozdělen na backend (ukládání těchto rozšířených typů) a frontend (zobrazování rozšířených typů v grafickém uživatelském rozhraní).
3.2.5.1
Backend
Vlastnosti kontaktu jsou v Thunderbirdu ukládány v instancích třídy nsIAbCard [9], která
bohužel postrádá možnost vylistování všech atributů kontaktu.
Pro získání hodnoty atributu kontaktu případně pro jeho editaci nabízí třída pouze
funkce getProperty a setProperty. Všechny atributy jsou typu string a tak změna se provádí
například voláním aCard.setProperty("FirstName","Karel");.
Aplikace si tedy bude muset pamatovat všechny přidané atributy pro jejich další používání (jejich změnu, či vyčištění kontaktu). Druhou možností by bylo vytvořit nad touto
instancí wrapper, který by ukládal atributy kontaktu do seznamu, přes který bychom mohli
listovat. Při tomto řešení by však bylo nutné přepsat kompletně funkce jádra Thunderbirdu
starající se o zobrazování položek kontaktů v grafickém rozhraní a jejich ukládání po editaci. Vzhledem k tomu, že rozšíření atributů v kontaktu není velké, navrhuji použít první
variantu.
Z instancí nsIAbCard budeme při každé synchronizaci vytvářet JSON (export kontaktu)
a opačně (import kontaktu). Toto budou mít na starost 2 funkce: importContactProperties
a exportContactProperties. Pro funkční serializaci aplikace bude muset znát i všechny defaultní atributy třídy nsIAbCard (kontakt neumí odstranit všechny svoje atributy). Editace
kontaktu se provede tak, že se nejdříve všechny jeho atributy odstraní (nastaví na prázdný
řetězec), pak teprve jsou nastaveny jeho atributy na nové hodnoty. Atributy (defaultní i
přidané) budou aplikaci dostupné přes globální objekt rozšíření.
Změny v atributech kontaktů budou následující:
∙ přidání typů k telefonním číslům,
∙ rozšíření počtu e-mailových adres,
∙ přidání typů k e-mailovým adresám,
20
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
∙ přidání typů k webovým stránkám,
∙ přidání IM účtů (uživatelské jméno, protokol, typ),
∙ přidání SIP účtů (uživatelské jméno, typ).
Hodnoty konkrétních typů budou převzaty z dokumentace k OS Android [10].
3.2.5.2
Frontend – GUI
Po rozšíření atributů kontaktu je nutné změnit i grafické rozhraní starající se o zobrazování
kontaktů tak, aby k těmto přidaným atributům měl uživatel přístup. K novým atributům budou namapovány ovládací prvky podle návrhu v obrázku B.1. O grafické uživatelské
rozhraní kontaktů se v Thunderbirdu starají XUL objekty abEditCardDialog.xul a abNewCardDialog.xul. Jejich volání bude překryto pomocí overlay tak, aby se při otevírání okna
s kontaktem otevřel současně i soubor cardDialogOverlay.xul, který bude zajišťovat přidání
elementů DOM stromu tohoto okna. Ovládací elementy se nejprve v .xul souboru nadefinují, následně bude implementována jejich obsluha (ukládání, přípustné hodnoty). Overlay
se vloží do souboru chrome.manifest, což je zaváděcí soubor zásuvného modulu do hostitelské aplikace. Tím je zajištěn vstup souborů s objekty starajícími se o zobrazování a ukládání
přidaných kontaktních atributů do jádra Thunderbirdu. Toto překrytí implicitních souborů
je ukázáno zde:
overlay chrome://messenger/content/addressbook/abEditCardDialog.xul
chrome://sync.extbrain.thunderbird/content/gui/cardDialogOverlay.xul
overlay chrome://messenger/content/addressbook/abNewCardDialog.xul
chrome://sync.extbrain.thunderbird/content/gui/cardDialogOverlay.xul
3.2.6
Použité nástroje
Pro vývoj zásuvného modulu budou použity následující nástroje:
IntelliJ IDEA
Pro psaní javascriptového kódu lze použít samozřejmě jakýkoli textový editor. Idea však
poskytuje dobré zvýrazňování syntaxe, podporu refaktoringu a našeptávání ze standardních
knihoven, tak z kódu vlastního projektu.
Venkman
Debugovací nástroj přímo jako zásuvný modul v Mozilla Thunderbird umožňuje pozastavit
vykonávání kódu přímo v aplikaci. Dobře použitelný při zobrazování obsahu proměnných,
také pro prozkoumávání zdrojových souborů jádra Thunderbirdu.
3.2. NÁVRH IMPLEMENTACE
21
DOM Inspector
Umožňuje prozkoumávání hierarchického stromu Document Object Model elementů v grafickém rozhraní. Užitečný hlavně při potřebě navázat na defaultní GUI novými ovládacími
prvky.
SQLite Manager
Nástroj pro kompletní management databáze SQLite, která je součástí Mozilla Thunderbird.
Zobrazení struktury jednotlivých tabulek včetně jejich obsahu usnadňuje ladění a optimalizaci databázových dotazů.
22
KAPITOLA 3. ANALÝZA A NÁVRH IMPLEMENTACE
Kapitola 4
ExtBrain Sync Protokol
Pro bezchybné realizování synchronizace je nutné definovat nejen formát zpráv, které budou
přenášeny, a typ úložiště, ale obecněji i protokol, podle kterého se bude řídit jednak komunikace klientské aplikace se vzdáleným úložištěm, ale i sled kroků prováděných nad lokálním
úložištěm. Na podrobný popis protokolu se zaměřuje následující kapitola.
4.1
Definice pojmů
Označme entitu určenou k synchronizaci jako položku (item). Položkou může být například
množina kontaktních informací, událost v kalendáři apod. Především při synchronizačním
přenosu lze místo pojmu položka užívat označení zpráva. Zpráva se skládá povinně z těla
(content) a nepovinně přílohy (attachment). Content je serializovaná položka v určitém
formátu (např. XML, JSON), má podobu textových dat. Attachment je soubor, který se
k položce váže. Může mít podobu textového nebo binárního souboru. Jedná se například
obrázek přiložený ke kontaktu. Účtem označujeme souhrn informací o synchronizovaném
lokálním adresáři, uživatelské jméno, adresu serveru, port, typ zabezpečení a název složky
na serveru. Synchronizace je jednorázová akce vyvolaná uživatelem či automaticky vedoucí
k dosažení stavu, kdy sobě obsahem a strukturou odpovídají položky v lokálním adresáři a
ve vzdáleném úložišti.
4.2
Označení položky
Položka je identifikována pomocí UUID (Universally Unique IDentifier) obsaženého v těle
zprávy. Synchronizačním protokolem je zajištěno, že se v úložišti v jednu chvíli nevyskytují
dvě zprávy se stejným UUID. Protokol přikládá každé verzi položky také unikátní RevId,
které slouží k rychlému odlišení verzí. Unikátnost tohoto identifikátoru je zaručena pomocí
IMAP protokolu.
23
24
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
4.3
Lokální a databázové úložiště
Lokální úložiště (adresář) je místo na lokálním zařízení (počítači, mobilním telefonu), které
má být synchronizováno se vzdáleným úložištěm. Pro podporu synchronizace slouží databázové úložiště uchovávájící informace o verzích položek. Databáze zajišťuje uchovávání těchto
informací o každé položce: UUID, RevId, tělo, hash přílohy, entryPresent (zdali položka v
lokálním úložišti existuje, nebo byla smazána) a účet, ke kterému se položka váže.
4.4
Vzdálené úložiště
Jako vzdálené úložiště synchronizace slouží složka (mailbox) v e-mailovém účtu na IMAP
serveru. Zprávy jsou do úložiště posílány pomocí IMAP protokolu dle RFC 3501. Zpráva je
pro tento přenos zabalena do IMAP zprávy dle RFC 822 (viz odstavec 3.1.3), ta je pomocí
příkazu APPEND uložena na server. RevId je v ExtBrain Sync protokolu označení pro
UID IMAP zprávy, které je IMAP protokolem vygenerováno vždy při vložení zprávy do
složky. IMAP zpráva obsahuje kromě jiných standardních hlaviček i řádek s UUID položky.
ExtBrain Sync protokol vyžaduje v hlavičce pouze tuto UUID položku, pro přehlednost jsou
však v IMAP zprávách ponechány i standardní hlavičky.
Ukázka hlavičky IMAP zprávy rozšířené o UUID záznam:
1
2
3
4
5
6
7
8
9
From: Archimedes Thunderbird testProfile <[email protected]>
Date: Tue, 03 Apr 2012 10:02:40 GMT
Subject: =?UTF-8?Q?Karel Jan=C3=A1k?=
To: [email protected]
uuid: d10a7f70-3a97-4ac9-8293-b0de38c95a3d
Message-Id: <ed4f2786b2284cbfb037291584f49393@libimap-client>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
V následujících podkapitolách jsou podrobně popsány jednotlivé fáze synchronizace. Začneme popisem výměny synchronizačních zpráv, na konci kapitoly je pak popsán způsob
zajištění unikátního přístupu do vzdáleného úložiště.
4.5
Fáze synchronizace
Proces synchronizace je možné rozdělit do tří hlavních fází (viz obr. 4.1).
Ve fázi import se kontaktuje vzdálené úložiště, zjišťuje se jeho aktuální stav a podle potřeby se z něj získají aktuální/nová data. Druhou fází (označenou jako core) je porovnávání
příchozích změn se stavem lokálních položek, jejich editace a případné vybrání pro závěrečnou fázi – export. V té se do vzdáleného úložiště ukládají změny, případně se odstraňují staré
verze položek. Není-li třeba měnit obsah vzdáleného úložiště, je fáze export vynechána.
4.6. FÁZE IMPORT
25
Obrázek 4.1: Fáze procesu synchronizace
4.6
Fáze import
Cílem této fáze je zjištění obsahu složky v e-mailové schránce. Data jsou předána dále ke
zpracování synchronizačnímu jádru. Získávání obsahu složky se děje ve třech krocích tak,
aby se minimalizoval datový přenos mezi klientskou aplikací a serverem.
Postup v této fázi je možné popsat jako sled těchto kroků:
1. získání UIDNEXT a EXISTS,
2. načtení hlaviček IMAP zpráv,
3. načtení těl a příloh nových zpráv.
Průběh kroků ve fázi import ukazuje také obrázek 4.2.
IMAP protokol udržuje nad složkou několik atributů, pro ExtBrain Sync protokol jsou
důležité následující dva: UIDNEXT a EXISTS. První označuje předpokládané UID příští
zprávy, která bude do složky uložena. Je-li UIDNEXT vyšší než bylo při poslední synchronizaci, do složky byla uložena nová zpráva. Změna tohoto atributu však označuje pouze
ten fakt, že zpráva s daným UID byla do složky přidána. Z pouhé změny UIDNEXT nelze
rozhodnout, zda tato zpráva ve složce stále existuje. Počet zpráv ve složce označuje druhý
parametr – EXISTS. Klientská aplikace musí zajistit lokální uložení obou těchto atributů
při každé synchronizaci. Tato dvojice se souhrnně označuje jako „stav účtu“.
Aby se nemusel získávat obsah všech zpráv ve složce, není-li to nezbytně nutné, v prvním
kroku se zjistí hodnoty UIDNEXT a EXISTS. Pokud se obě tyto hodnoty rovnají hodnotám
z předchozí synchronizace, ve vzdálené složce nedošlo k žádným změnám a není proto nutné
obsah úložiště dále načítat. (Protože IMAP zprávy na serveru není možné editovat, je zajištěno, že zprávy se stávajícím UID mají stejný tvar, jako při odesílání klientem. Z této situace
26
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
Obrázek 4.2: Stavový diagram fáze import
lze vyvodit závěr, že aktuální klientská aplikace byla poslední, která ve vzdáleném úložišti
prováděla změny.) Liší-li se alespoň jedna z hodnot, je nutné přistoupit ke druhému kroku,
kterým je načtení hlaviček IMAP zpráv. Pokud se stav účtu liší v UIDNEXT a zprávy s
vyšším nebo rovným UID než je lokální UIDNEXT ve složce na serveru existují, je nezbytné
získat jejich kompletní obsah, což je zároveň třetím a záverečným krokem této fáze.
V následujících odstavcích je podrobnější popis kroků prováděných ve fázi import.
4.6.1
Získání UIDNEXT a EXISTS
Atributy složky UIDNEXT a EXISTS se vyskytují v odpovědi IMAP serveru na příkaz
SELECT (vybrání složky pro přístup ke zprávám uvnitř). Požadované atributy se tedy získají jednorázovým zavoláním příkazu SELECT s parametrem názvu složky a vyparsováním
hodnot pomocí regulárních výrazů.
Ukázka získání atributů UIDNEXT a EXISTS je v následujícím výpisu. Řádek 1 obsahuje příkaz klientské aplikace, další řádky odpověď serveru. Řetězec a003 před příkazem je
tzv. tag umožňující identifikovat odpověď serveru na daný příkaz při asynchronních voláních.
V tomto případě je vybrána složka „extbrainContacts“, hodnota UIDNEXT je rovna 988 a
ve složce existuje 5 zpráv.
1
2
3
4
5
a003 SELECT extbrainContacts
* FLAGS (\Answered \Flagged \Draft \Deleted \Seen, Seen Test lock)
* OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen,
Seen Test lock \*)] Flags permitted.
* OK [UIDVALIDITY 660858846] UIDs valid.
4.6. FÁZE IMPORT
6
7
8
9
27
* 5 EXISTS
* 0 RECENT
* OK [UIDNEXT 988] Predicted next UID.
a003 OK [READ-WRITE] extbrainContacts selected. (Success)
4.6.2
Načtení hlaviček IMAP zpráv
Příkaz FETCH slouží v protokolu IMAP k získávání zpráv. Příkaz vyžaduje dva parametry:
číselné označení sekvence požadovaných zpráv a vyžadované prvky zprávy (např. jen některé položky hlavičky, tělo, přílohu). UID FETCH má stejné použití, jen se jako parametr
označující sekvenci získávaných zpráv udává UID zprávy namísto pořadí zprávy ve složce.
Hlavičky zpráv získáme jednorázovým odesláním příkazu UID FETCH s parametrem pro
získání všech zpráv (UID zpráv 1 až *) a BODY[HEADER.FIELDS (UUID)] pro získání UUID
řádku z hlavičky IMAP zprávy.
Ukázka komunikace klienta se serverem pro získání hlaviček IMAP zpráv.
1
2
3
4
5
6
7
8
9
10
11
12
a004 UID FETCH 1:* BODY[HEADER.FIELDS (UUID)]
* 1 FETCH (UID 892 BODY[HEADER.FIELDS (UUID)]
uuid: e0be92ae-1a96-4d74-a4f3-1aca8936fdf6)
* 2 FETCH (UID 910 BODY[HEADER.FIELDS (UUID)]
uuid: 2906f0f4-4958-4be4-904a-b80f4af3ceeb)
* 3 FETCH (UID 915 BODY[HEADER.FIELDS (UUID)]
uuid: d86d2e79-0f4b-4504-822f-b7529d7d8bf6)
* 4 FETCH (UID 923 BODY[HEADER.FIELDS (UUID)]
uuid: c6d7c601-a11c-46fb-b96c-733f9c6a9dd9)
* 5 FETCH (UID 987 BODY[HEADER.FIELDS (UUID)]
uuid: 6ace5e74-97a1-4502-9b56-069caa33485c)
a004 OK Success
{46}
{46}
{46}
{46}
{46}
Z odpovědi serveru (řádky 2 – 12) je vytvořen seznam položek ve tvaru <UUID : RevId>
(RevId=UID zprávy). Příklad takové struktury vytvořené z předchozí odpovědi serveru je
v tabulce 4.1.
UUID
e0be92ae-1a96-4d74-a4f3-1aca8936fdf6
2906f0f4-4958-4be4-904a-b80f4af3ceeb
d86d2e79-0f4b-4504-822f-b7529d7d8bf6
c6d7c601-a11c-46fb-b96c-733f9c6a9dd9
6ace5e74-97a1-4502-9b56-069caa33485c
RevId
892
910
915
923
987
Tabulka 4.1: Načtení hlaviček IMAP zpráv - výsledek
28
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
4.6.3
Načtení těl a příloh nových zpráv
Nové zprávy (nově přidané od poslední synchronizace) jsou ty, které mají v tabulce hlaviček
RevId vyšší nebo rovno lokálnímu UIDNEXT. Tyto zprávy je na rozdíl od ostatních nutné
získat celé, k tomu se využije opět příkazu UID FETCH. Po serveru požadujeme celé tělo
zprávy, proto jako druhý parametr použijeme BODY[TEXT].
Příkaz na získání zprávy s RevId 923 z tabulky 4.1 tak bude vypadat takto: UID FETCH
923:923 BODY[TEXT]. Ukázka komunikace nutné k získání této zprávy je zde:
1
2
3
4
5
a005 UID FETCH 923:923 BODYTEXT
* 5 FETCH (UID 65 FLAGS (\Seen) BODYTEXT {451}
--e0cb4efe319222759c04bd6bef7a
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
6
7
8
{"name":"Karel Pol=C3=A1=C5=A1ek","uuid": "c6d7c601-a11c-46fb-b96c-733f9=
c6a9dd9"}
9
10
11
12
13
14
--e0cb4efe319222759c04bd6bef7a
Content-Type: image/png; name="karel.png"
Content-Disposition: attachment; filename="karel.png"
Content-Transfer-Encoding: base64
X-Attachment-Id: f_h0wr2yuw0
15
16
17
18
b2JyYXplaw==
--e0cb4efe319222759c04bd6bef7a--)
a005 OK Success
V řádku 1 je příkaz klientské aplikace včetně úvodního tagu. Řádky 7 a 8 obsahují tělo
zprávy, řádek 16 base64 reprezentaci souboru s názvem karel.png v příloze.
Tělo zprávy obsahuje serializovanou podobu synchronizované položky. Tělo zprávy a příloha jsou přidány do odpovídajícího řádku seznamu z předchozí sekce. Tento seznam položek
nyní již ve tvaru <UUID : RevId, content, attachment> je výstupem tohoto kroku a je
předán dále synchronizačnímu jádru. Ukázka této struktury je v tabulce 4.2. V řádku s RevId 923 vidíme tělo zprávy a přílohu tak, jak byly přijaty v tomto kroku. Poté byla získána
ještě zpráva s RevId 987, ta přílohu neobsahuje.
4.7
Synchronizační jádro
Úkolem této ústřední fáze procesu synchronizace je učinit všechny „lokální“ kroky potřebné
pro nastolení konzistentního stavu mezi vzdáleným úložištěm a místním adresářem. To zahrnuje práci s lokálními položkami (vyhledání změn, serializace), vytvoření synchronizační
tabulky, její procházení a vykonávání editací položek, přípravu položek pro exportní fázi
(odeslání položek, či jejich odstraňění).
Kroky synchronizačního jádra ukazuje obrázek 4.3.
4.7. SYNCHRONIZAČNÍ JÁDRO
UUID
e0be92ae...
2906f0f4...
d86d2e79...
c6d7c601...
RevId
892
910
915
923
6ace5e74...
987
content
{"name":"Karel
Polášek","uuid":
"c6d7c601-a11c-46fb-b96c733f9c6a9dd9"}
{"name":"Jakub Nový","uuid": "6ace5e7497a1-4502-9b56-069caa33485c"}
29
attachment
karel.png
Tabulka 4.2: Načtení těl IMAP zpráv - výsledek
Obrázek 4.3: Stavový diagram jádra synchronizace
V následujících dvou podkapitolách se zaměříme na popis kroků v synchronizačním jádru.
Ty jsou dva: vytvoření synchronizační tabulky a její následné procházení.
4.7.1
Vytvoření synchronizační tabulky
Základem synchronizační tabulky jsou data získaná z předchozí fáze import. Tento krok
má za úkol přidat verze položek v lokálním adresáři a verze z databáze. Cílem je vytvoření struktury podobné tabulce 3.1. Místo pouhých čísel revizí budou však v této struktuře
textové reprezentace verzí, toho je zapotřebí pro řešení kolizí v dalším kroku. Protože číslo
RevId je lokálním položkám přidělováno až prostřednictvím IMAP protokolu při uložení
na server, jsou lokální položky zastoupeny pouze textovou reprezentací verze. Hotovou synchronizační tabulku pro příklad z předchozí fáze ukazuje tabulka 4.3. Attachment je místo
názvu souboru převeden na hash. UUID a content jsou pro účel této tabulky zkráceny.
Inicializace seznamu položek z databáze
Skončila-li fáze import po kroku 1 (získání UIDNEXT a EXISTS) bez vytvoření seznamu
položek a není tudíž seznam položek inicializován, je nutné jej vytvořit nyní. Pokud seznam
30
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
row
1
remote
UUID RevId content
e0be
892
2
2906
910
3
d86d
915
4
c6d7
923
5
6ace
987
6
186a
Karel
Polášek
Jakub
Nový
hash
1231
database
RevId content
892
Pavel
Stejný
910
Tomáš
Změna
915
Jan
Starý
914
Karel
Poláczek
913
hash
1231
Josef
Smazaný
local
content hash
Pavel
Stejný
Tomáš
7323
Změna
Karel
Poláček
1231
Josef
Smazaný
Tabulka 4.3: Synchronizační tabulka - hodnoty mají ilustrační charakter (UUID a content
jsou zkráceny, hash je výsledek hashovací funkce zavolané na soubor v příloze)
nebyl vytvořen, znamená to, že se ve vzdáleném úložišti nevyskytují změny, a tak je možné
vytvořit obraz tohoto seznamu lokálně pomocí výběru položek z databáze. Pro tento účel
slouží atribut entryPresent, který je v databázi uložen pro každou položku. Při vytváření
obrazu položek ve vzdáleném úložišti vybíráme z databáze právě ty položky, které mají
atribut entryPresent nastaven na true. S tímto seznamem položek pak lze pracovat stejně
jako by byl získán ze vzdáleného úložiště ve fázi import.
Přidávání verzí do tabulky
Následující popis přidávání verzí do tabulky se vztahuje k tabulce 4.3.
Při vytváření tabulky je nejprve nutné k položkám získaným ze serveru přidat verze
z lokálního adresáře a z databáze (řádky 1, 2, 4). Za databázovou verzi je považována verze
s nejvyšším RevId pro danou položku. Poté se přidávají všechny lokální položky, které ve
struktuře z fáze import chybí - byly ze serveru odstraněny (řádek 6). Nakonec se porovnává
stav lokálního adresáře s databází přes atribut entryPresent a přidávají se položky, které
byly lokálně od poslední synchronizace smazány (hledají se takové, které mají v databázi
entryPresent==true, ale v adresáři neexistují, řádek 3). Do řádku 5 nebyly přidány žádné
údaje, položka není v lokálním adresáři ani v databázi zastoupena.
Absence těla zprávy a hashe ze vzdáleného úložiště je v řádcích 1 až 3 dána tím, že nebyly
stahovány celé zprávy, ale pouze hlavičky obsahující UUID a RevId. Pomocí parametrů
UIDNEXT a EXISTS je zaručeno, že obsah zprávy není nutné stahovat ze serveru, protože
jej lze jednodušším způsobem získat z databáze. Protokolem je zajištěno, že databáze pro
tyto položky verze s danými RevId obsahuje, jak lze vidět ve sloupci database u těchto
řádků.
4.7. SYNCHRONIZAČNÍ JÁDRO
4.7.2
31
Procházení synchronizační tabulky
V tomto kroku synchronizace dochází k průchodu synchronizační tabulkou, manipulaci s
položkami a přípravou pro zapsání nových verzí do vzdáleného úložiště.
Před vyhodnocováním změn v hodnotách jednotlivých verzí se podívejme na každý řádek z globálního pohledu a rozlišujme mezi situacemi, kdy položka v jednotlivých úložištích
existuje, či nikoli. Situace, které mohou z tohoto úhlu pohledu nastat, lze popsat pomocí binárních řetězců. Máme tři možná úložiště, verze v daném úložišti je zastoupena (označme 1),
nebo chybí (0). Z toho plyne, že nastává celkem 23 = 8 možných situací, které můžeme nejprve rozlišit. Seřadíme-li úložiště například v pořadí remote, database, local, lze situace
označit pomocí binárních řetězců vzestupně od 000 po 111.
Některé ze situací však nejsou „platné“. Například situace označená jako 000, kdy položka
není v žádném z úložišť, nemůže nastat, neboť by se tak neměla jak dostat do synchronizační
tabulky. Obdobně je tomu se situací označenou jako 010, kdy je položka zastoupena pouze
v databázi. To by znamenalo, že položka existovala ve vzdáleném a lokálním úložišti a byla
odtud odstraněna. (Při odstranění se však příznak položky entryPresent v databázi nastaví
na false a položka se při dalším vytváření synchronizační tabulky ignoruje.) Všechny ostatní
situace označené binárními řetězci jsou platné, nejkomplexnější je samozřejmě situace 111,
kdy jsou verze dané položky zastoupeny ve všech úložištích. Touto situací, pro jejíž vyřešení
potřebujeme znát již konkrétní hodnoty verzí se budeme zabývat později. Všechny situace,
které mohou nastat jsou včetně popisu v tabulce 4.4.
remote
0
0
0
0
1
1
1
1
database
0
0
1
1
0
0
1
1
local
0
1
0
1
0
1
0
1
popis situace
neplatné
nová lokální položka
neplatné
položka ve vzdáleném úložišti smazána
nová položka ve vzdáleném úložišti
účet odstraněn a vytvořen nový, položka ponechána
položka v lokálním úložišti smazána
nelze takto rozhodnout
Tabulka 4.4: Možné situace v synchronizační tabulce (1 označuje prezenci verze, 0 absenci,
popis označuje, co se stalo od poslední synhronizace)
Popis algoritmu průchodu tabulkou
Průchod tabulkou lze nejlépe popsat přímo pseudokódem, jeho zápis je v algoritmu 4.1. Z
důvodů zjednodušení je v algoritmu vynecháno řešení specifického případu, který bychom
mohli označit jako situace 101. Ta znamená, že položka chybí pouze v databázi. Toto se
může při spoléhání na fakt, že neexistují dvě různé položky se stejným UUID, stát pouze v
situaci, kdy jsou databázová data odstraněna bez odstranění položek v lokálním a vzdáleném
úložišti.
32
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
Algoritmus je realizován jako for cyklus, v němž se prochází přes všechny položky v
tabulce. Uvnitř for cyklu jsou nejprve umístěny 4 podmínky zjišťující prezenci a absenci
položek v jednotlivých lokacích – vzdálené, lokální úložiště a databáze (řádky 2 až 17).
Splňuje-li položka určitou podmínku, je vyvolána akce přidružená k dané situaci a pomocí
continue se ukončí běh for cyklu pro tuto položku. Tato úvodní sada podmínek zahrnuje
situace, kdy položka je na lokální nebo vzdálené straně nově vytvořena, případně odstraněna.
Nesplňuje-li položka ani jednu z podmínek, znamená to, že v tabulce existují verze pro
všechna úložiště. Manipulace s položkou už tedy nebude pouze v mezích „vytvoř novou“,
případně „smaž“, bude se jednat o přepis verze položky.
Pro další postup je nutné zjistit, zdali byla položka v lokálním adresáři změněna. K
tomu slouží podmínka na porovnání databázové a lokální verze (od řádku 18 po 33). Tato
podmínka se dále větví a je rozkreslena na obrázku 4.4.
Obrázek 4.4: Poslední krok průchodu synchronizační tabulkou (v algoritmu 4.1 řádky 18 až
33)
Neliší-li se databázová a lokální verze, položka změněna nebyla a můžeme tedy přijmout
změnu. Pokud se liší (položka byla změněna), porovnají se ještě RevId z databáze a ze
vzdáleného úložiště. Rovnají-li se RevId, bude lokální verze (změna) zapsána na server,
nerovnají-li se, došlo k situaci, kdy byla změna položky provedena jednak v lokálním, tak ve
vzdáleném úložišti a dochází ke kolizi. Při obsluze kolize je doporučeno zkontrolovat, zdali
není lokální a vzdálená verze obsahem stejná. Více o kolizích a jejich řešení je v podkapitole
Princip synchronizace.
4.7. SYNCHRONIZAČNÍ JÁDRO
33
Algoritmus 4.1 procházení synchronizační tabulky
1: for all item in syncTable do
000 neplatné
001:
2:
if ( !item.remote && !item.database && item.local ) then
3:
objectsToExport.push(item);
◁ položka vybrána pro export
4:
continue;
5:
end if
010 neplatné
011:
6:
if ( !item.remote && item.database && item.local ) then
7:
deleteLocal(item);
◁ smazat položku lokálně
8:
continue;
9:
end if
100:
10:
if ( item.remote && !item.database && !item.local ) then
11:
createLocal(item);
◁ vytvoření nové lokální položky
12:
continue;
13:
end if
101: vynechána
110:
14:
if ( item.remote && item.database && !item.local ) then
15:
objectsToDelete.push(item);
◁ položka vybrána pro smazání
16:
continue;
17:
end if
111:
18:
if ( equals( item.local, item.database ) ) then
◁ verze se sobě rovnají
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
if ( item.remote.RevId > item.database.RevId ) then
editLocalEntry(item);
◁ změň lokální položku
continue;
end if
continue;
◁ všechny verze se rovnají, nedělej nic
else
◁ verze se sobě nerovnají
if ( item.remote.RevId == item.database.RevId ) then
objectsToExport.push(item);
◁ položka vybrána pro export
continue;
end if
if ( item.remote.RevId > item.database.RevId ) then
handleCollision(item);
continue;
end if
end if
end for
◁ kolize
34
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
Všimněme si také řádku 23 a příkazu continue hned za předchozí podmínkou. K vykonání tohoto příkazu dojde tehdy, není-li položka lokálně ani vzdáleně změněna (remote.RevId
== database.RevId) a není proto potřeba s ní nijak manipulovat. Za připomenutí stojí, že
protokolem je zajištěno, že nedojde k situaci, kdy remote.RevId < database.RevId. Podmínky na tyto situace jsou tedy vypuštěny.
Příklad průchodu konkrétní tabulkou
Pro příklad z předchozích odstavců by průchod tabulkou 4.3 vypadal následovně:
1. řádek: UUID e0be má zastoupení ve všech lokalitách, ve všech ve stejné verzi, tudíž splní
podmínku algoritmu průchodu tabulkou z řádku 18. I RevId se rovnají, proto se
podle řádku 23 s touto položkou manipulovat nebude.
2. řádek: UUID 2906 má taktéž zastoupení ve všech lokalitách, lokální však obsahuje kromě
těla položky i hash přílohy a tím se liší od verze v databázi. Tato položka tedy
nesplní podmínku v řádku 18. RevId vzdálené a databázové verze se shodují, proto
bude v řádku 26 vybrána pro export do vzdáleného úložiště.
3. řádek: UUID d86d má zastoupení pouze ve sloupci remote a database, v lokálním úložišti tedy neexistuje a to je známka toho, že odsud byla odstraněna. Po splnění
podmínky v řádku 14 bude vybrána pro smazání ve vzdáleném úložišti.
4. řádek: UUID c6d7 je zastoupeno ve všech třech lokalitách. Všimněme si, že ale pokaždé
v jiné verzi. Původní jméno „Karel Poláczek“ bylo lokálně upraveno na „Karel
Poláček“, zatímco ve vzdáleném úložišti na „Karel Polášek“. Hashe příloh se neliší, příloha změněna nebyla. Položka tedy byla od poslední synchronizace lokálně
změněna, navíc byla načtena v nové verzi ze vzdáleného úložiště, nesplní tedy
porovnávací podmínku v řádku 18. RevId ze vzdáleného úložiště je vyšší než z
databáze a proto nastává kolize.
5. řádek: UUID 6ace je obsaženo pouze ve sloupci remote, což znamená, že nebylo klientem
ještě registrováno. Položka splní podmínku v řádku 10 a bude tak lokálně nově
vytvořena. Zároveň s tím bude do databáze přidán tento záznam (hodnoty jsou
opět v plném tvaru, content a UUID vzato z tabulky 4.2):
UUID
RevId
content
:
:
:
hash
entryPresent
:
:
6ace5e74-97a1-4502-9b56-069caa33485c
987
{"name":"Jakub Nový","uuid": "6ace5e74-97a1-4502-9b56069caa33485c"}
true
6. řádek: UUID 186a je zastoupeno pouze ve sloupcích local a database. Ze vzdáleného
úložiště tedy musela být tato položka jiným klientem odstraněna. Položka splní
podmínku v řádku 6 a bude lokálně odstraněna. Po odstranění se u databázové
verze položky (RevId 913) nastaví atribut entryPresent na false.
4.7. SYNCHRONIZAČNÍ JÁDRO
35
Zápis verzí do databáze
Při průchodu se provádějí také zápisy verzí do databáze, ale pouze u položek, jejichž lokální
verze je přepisována verzí ze vzdáleného úložiště. U těchto verzí je totiž již znám atribut verze
RevId. U položek, které byly změněny lokálně a budou exportovány se zápis do databáze
provádí až po zapsání do vzdáleného úložiště – po přidělení RevId IMAP protokolem. Při
vkládání nové verze do databáze se musí zabezpečit nastavení atributu entryPresent na false
u předchozí verze. Taktéž musí být tento atribut změněn při odstranění položky.
Příprava pro exportní fázi
Vybrání položky pro exportní fázi procesu synchronizace je realizováno jako přidání do
struktury objectsToExport případně objectsToDelete. Výstupem synchronizačního jádra
jsou tedy tyto dva objekty. Jsou-li oba tyto objekty prázdné, synchronizace je ukončena
a k fázi export se nepřistupuje.
Ukázka výstupu pro náš příklad je v tabulkách 4.5 a 4.6. Všimněme si druhého řádku
objectsToExport s položkou, která vyvolala kolizi. Uživatel ji vyřešil tak, že dal v atributu
jméno přednost lokální verzi (Karel Poláček) a od položky odstranil přílohu.
objectsToExport:
remote
UUID RevId content
2906
910
c6d7
923
Karel
Polášek
hash
1231
database
RevId content
910
Tomáš
Změna
914
Karel
Poláczek
hash
1231
local
content hash
Tomáš
7323
Změna
Karel
Poláček
Tabulka 4.5: Příklad struktury objektu objectsToExport
objectsToDelete:
remote
UUID RevId content
d86d
915
hash
database
RevId content
915
Jan
Starý
hash
local
content hash
Tabulka 4.6: Příklad struktury objektu objectsToDelete
36
4.8
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
Fáze export
Fáze export má za úkol využít protokol IMAP k zapsání nových verzí položek na vzdálené
úložiště a odstranění (resp. přesunutí) starých, pokud je toho při synchronizaci zapotřebí.
Využívá k tomu struktur přicházejících od synchronizačního jádra, těmi jsou verze položek
srovnané v objektech objectsToExport a objectsToDelete. Protože IMAP protokol neumožňuje zprávy na serveru editovat, musí se nové verze položek na server uložit a staré verze
přesunout do jiné složky. Přesouvat se budou nejen položky z objectsToDelete, ale i položky
z objectsToExport, které obsahují záznam ve sloupci remote. V našem příkladu v tabulce
4.5 to jsou všechny položky. Je však nutné mít na paměti, že pokud by některá z položek
byla v lokálním úložišti nově vytvořena, byla by na server pouze zapsána bez následného
přesouvání předchozí verze, ta ostatně ani neexistuje.
Pro uchovávání historie nejsou zprávy ze serveru trvale odstraňovány, jsou pouze přesunuty do podsložky „Deleted“. Pro další synchronizace však nejsou tyto verze potřebné a tak
při nutnosti uvolnit místo na serveru mohou být z této složky kdykoli odstraněny.
Fázi export lze rozdělit do dvou navazujících kroků: krok zápisu a krok přesouvání. V
obrázku 4.5 označeno jako APPEND a MOVE. Je-li objectsToExport prázdný, přikračuje
se rovnou ke kroku přesování.
Obrázek 4.5: Stavový diagram fáze export
4.8. FÁZE EXPORT
4.8.1
37
Krok zápisu
Zápis položky na server je realizován pomocí IMAP příkazu APPEND se dvěma povinnými
parametry: složkou a obsahem zprávy (hlavička, tělo a příloha). K tělu a příloze položky
tedy musí být vygenerována standardní IMAP hlavička rozšířená o UUID záznam. Ukázka
této rozšířené hlavičky je v podkapitole Vzdálené úložiště. Do těla IMAP zprávy je vložena
serializovaná podoba těla položky, případná příloha je ve formátu base64. Jako tělo položky
je vždy brána lokální verze, to je ostatně přesně účelem tohoto kroku, exportovat lokální
verze.
Ukládání zpráv probíhá postupně po jedné položce procházením přes pole objectsToExport. Ve stavovém diagramu je to naznačeno cyklem kolem stavu APPEND. Odpověď
serveru na příkaz APPEND obsahuje UID nově přidané zprávy. UID je od této chvíle RevId
této verze položky a je spolu s tělem položky a hashem přílohy zapsáno do databáze.
Příklad
Komunikace mezi klientem a serverem během zápisu jedné IMAP zprávy je ukázána v následujícím výpisu. V něm se zapisuje položka z druhého řádku objectsToExport (tabulka
4.5). Řádek 1 obsahuje příkaz klienta, číslo 817 označuje délku zprávy ve znacích. Následuje hlavička zprávy (řádky 2 až 9). Na řádcích 15 a 16 je vidět serializované tělo položky
(tentokrát opět v nezkráceném tvaru, je uveden celý JSON včetně UUID položky), přílohu
položka neobsahuje, proto je vynechána. Poslední řádek ukazuje standardní odpověď klienta
na takový příkaz. Za APPENDUID je nejdříve uvedeno UIDVALIDITY a pak UID zprávy.
Toto UID se stane novým RevId této položky.
1
2
3
4
5
6
7
8
9
a006 APPEND extbrainContacts {817}
From: Archimedes Thunderbird testProfile <[email protected]>
Date: Fri, 13 Apr 2012 18:56:37 GMT
Subject: =?UTF-8?Q?Karel Pol=C3=A1=C4=8Dek?=
To: Imap Test <[email protected]>
uuid: 18c34b9c-d4fb-4ff3-b4d4-3d7aaf64c522
Message-Id: <da40e5efa35f40079a82b423f8ac2409@libimap-client>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary=a5a5fd7524ac42f5a61b434e568f7deb
10
11
12
13
--a5a5fd7524ac42f5a61b434e568f7deb
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
14
15
16
17
18
{"name":"Karel Pol=C3=A1=C4=8Dek","uuid":"c6d7c601-a11c-46fb-b96c-73=\r\n
3f9c6a9dd9"}
--a5a5fd7524ac42f5a61b434e568f7deb-a006 OK [APPENDUID 660858846 988] (Success)
Verzi položky bylo tedy přiděleno RevId s hodnotou 988, ihned po zapsání zprávy do vzdáleného úložiště je do databáze přidán záznam o nové verzi položky.
38
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
UUID
RevId
content
:
:
:
hash
entryPresent
:
:
18c34b9c-d4fb-4ff3-b4d4-3d7aaf64c522
988
{"name":"Karel Poláček",
"uuid": "18c34b9c-d4fb-4ff3-b4d4-3d7aaf64c522"}
true
Zároveň je u předchozí verze položky (RevId 914 viz tabulka 4.3) nastaven atribut entryPresent na false.
4.8.2
Krok přesouvání
K přesunutí jsou určeny remote verze položek ze struktury objectsToDelete a objectsToExport. Položky v objectsToExport neobsahující remote verzi nejsou určeny k přesouvání.
Protože IMAP protokol neobsahuje příkaz pro přesunutí zprávy (MOVE), ale pouze
COPY pro zkopírování, přesunutí je realizováno jako kopírování zprávy do cílové složky a
její následné odstranění ze složky původní. Pro odstraňování zpráv je v protokolu vyčleněn
příkaz EXPUNGE, který jednorázově odstraní všechny zprávy ve složce označené příznakem
\Deleted, přičemž příznaky se zprávám přidávají pomocí příkazu STORE.
Přesouvání je tedy realizováno operacemi v tomto sledu:
1. zkopírování přesouvaných zpráv do podsložky „Deleted“,
2. nastavení příznaku \Deleted k originálům zpráv,
3. trvalé odstranění zpráv s tímto příznakem.
První dvě operace jsou realizovány postupně po jedné zprávě, voláním příkazů UID
COPY resp. UID STORE. UID COPY vyžaduje jako parametr sekvenci zpráv a název
složky, do které se mají zprávy zkopírovat. UID STORE sekvenci zpráv a příznak, který má
být zprávě přidán. Po každém volání UID STORE se pro dané číslo RevId v databázi změní
hodnota atributu entryPresent na false. Po nastavení příznaku ∖Deleted poslední zprávě
je zavolán příkaz EXPUNGE na vyčištění složky. Tak jsou zkopírované zprávy odstraněny.
Tím je dosaženo stavu, kdy si obsah složky vzdáleného úložiště s lokální složkou odpovídají,
synchronizace je tím ukončena.
Příklad
Příkazy volané ve fázi export pro náš příklad ukazuje následující výpis komunikace klientserver. Pro přehlednost jsou volání klienta zvýrazněna. Z tabulek struktur objectsToExport a
objectsToDelete je vidět, že zprávy k přesunutí jsou celkem 3 (RevId 915 z objectsToDelete,
910 a 923 z objectsToExport). Příkazy UID COPY a UID STORE jsou tudíž volány každý
třikrát. V odpovědi na příkaz UID COPY jsou vidět parametry zprávy nově přidané do
podsložky, v odpovědi na UID STORE aktuální stav příznaků u zprávy a počet zbývajících
zpráv ve složce (pro ExtBrain Sync není důležité).
4.9. PARALELNÍ PŘÍSTUP
1
2
39
A004 UID COPY 915:915 extbrainContacts/Deleted
A004 OK [COPYUID 660858847 915 43] (Success)
3
4
5
A005 UID COPY 910:910 extbrainContacts/Deleted
A005 OK [COPYUID 660858847 910 44] (Success)
6
7
8
A006 UID COPY 923:923 extbrainContacts/Deleted
A006 OK [COPYUID 660858847 923 45] (Success)
9
10
11
12
13
14
A007 UID STORE 915:915 +FLAGS (\Deleted)
* 6 FETCH (FLAGS (\Seen \Deleted) UID 915)
* 6 EXPUNGE
* 5 EXIST
A007 OK Success
15
16
17
18
A008 UID STORE 910:910 +FLAGS (\Deleted)
...
A008 OK Success
19
20
21
22
A009 UID STORE 923:923 +FLAGS (\Deleted)
...
A009 OK Success
23
24
25
A010 EXPUNGE
A010 OK Success
4.9
Paralelní přístup
Protokol je navržen tak, že podporuje současný přístup pouze jedné klientské aplikace.
Během synchronizačního procesu nastávají chvíle, kdy jsou data ve vzdáleném úložišti v nekonzistentním stavu (typicky mezi uložením nové verze položky a odstraněním staré). Pokud
by v tuto chvíli jiný klient načítal ze vzdáleného úložiště, budou jím získané údaje neúplné.
Pro zamezení současného přístupu více klientů najednou jsou v protokolu synchronizační
zámky.
4.9.1
Zamykání vzdáleného úložiště
Klient se před zahájením importní fáze synchronizace pokusí zamknout nad vzdáleným
úložištěm zámek. Jako zámky slouží IMAP zprávy ukládané do podsložky „lock“. Při pokusu
o zamčení úložiště klient do této složky vloží zprávu, které je přiděleno serverem jednoznačné
UID. Žádá-li o zamčení více klientů najednou, jejich zprávy se do složky zařadí postupně
jako do fronty. Pokračovat v synchronizaci však bude pouze jeden z nich; ten, jenož zpráva
reprezentující zámek byla do složky vložena nejdříve.
Klientská aplikace tedy ověří, zda je jím odeslaná zpráva na prvním místě. To je implementováno jako získání nejstarší zprávy ve složce. Shoduje-li se UID této zprávy a zprávy,
40
KAPITOLA 4. EXTBRAIN SYNC PROTOKOL
kterou klientská aplikace na server odeslala, úložiště je úspěšně uzamčeno pro danou aplikaci
a ta může pokračovat v synchronizaci. Pokud se tato UID neshodují, složka byla uzamčena
jiným klientem a aktuální klient svůj zámek ze složky odstraní. Stejně tak i klient, který
pro svoji potřebu úložiště úspěšně zamkl, po dokončení synchronizace odemkne úložiště
odstraněním svého zámku.
Stavový diagram zamykání vzdáleného úložiště je na obrázku 4.6.
Obrázek 4.6: Stavový diagram zamykání vzdáleného úložiště
Kapitola 5
Realizace
5.1
Obecný synchronizační modul
Obecný synchronizační modul informací je implementován několika třídami, prostřední vrstvu
tvoří třída CommonSync. Diagram tříd synchronizačního modulu je na obrázku 5.1. Třídy
ItemSync a RemoteStorageHandler jsou abstraktní. V class diagramu ukazují, jaké metody musí mít jejich konkrétní implementace, aby s nimi dokázala CommonSync komunikovat. Konkrétními implementacemi jsou ContactSync (rozšíření modulu o synchronizaci kontaktů), ImapSync a ImapSyncController (realizace spodní vrstvy architektury pro podporu
IMAP úložiště). Pomocí atributů this.itemsAPI a this.communicationAPI jsou v CommonSync uchovány reference na instance těchto konkrétních tříd. Struktura položek a synchronizační tabulky byla uvedena již v definici protokolu, není tedy třeba ji zde znovu uvádět.
5.1.1
Průběh volání v jednotlivých fázích synchronizace
Sekvenční diagram celého procesu synchronizace je na obrázku B.2 v příloze této práce. V
následujících odstavcích je rozebrán flow programu po jednotlivých fázích.
Fáze import
První fáze synchronizace je celá realizována pomocí vrstvy remote storage. V případě vzdáleného úložiště IMAP konkrétně objektem třídy ImapSync a ImapSyncController. Objekt
commonSync volá this.communicationAPI.import(this) pro zahájení importu. Metodě je v
parametru předáno scope, aby po sérii asynchronních voláních v IMAP knihovně dokázal
vrátit běh synchronizace k druhé fázi – jádru synchronizace. Po načtení položek ze vzdáleného úložiště tedy obsluha IMAP knihovny (ImapSyncController) vrací běh programu
pomocí scope.callMakeSyncTable(incommingItems) zpět do třídy CommonSync.
Sekvenční diagram volání při importní fázi je na obrázku 5.2.
41
42
KAPITOLA 5. REALIZACE
Obrázek 5.1: Class diagram synchronizačního modulu
Fáze synchronizační jádro
První krok synchronizačního jádra – vytvoření synchronizační tabulky – obstarává horní
vrstva synchronizace, volá se proto this.itemsAPI.makeSyncTable(incommingItems). Třída
implementující toto items API musí zajistit vytvoření synchronizační tabulky dle definice v
kapitole ExtBrain Sync Protokol. Volání v horní vrstvě nejsou asynchronní, proto může být
synchronizační tabulka předána zpět do CommonSync přes návratovou hodnotu. Průchod
synchronizační tabulkou je implementován v metodě handleSyncTable třídy CommonSync.
Zde jsou uvnitř cyklu implementovány podmínky pro nastalé situace přesně podle definice
v protokolu. Obsluhu situací podporují metody initialItemHandling, createItem, deleteItem,
acceptChange a handleCollision, (tyto nejsou pro zjednodušení uvedeny v class diagramu).
Uvnitř těchto metod totiž neprobíhá fyzická manipulace s položkami (třída Common sync
toto ani neumí), pouze se zde volají příslušné metody z items API, probíhá update verzí v
databázi, případně se položky vkládají do objectsToExport a objectsToDelete.
Fáze export
Exportní fáze je opět celá v režii vrstvy remote storage. Třídě implementující tuto vrstvu
jsou předány objekty objectsToExport, objectsToDelete a scope, aby po uložení položek na
server mohla ohlásit konec synchronizačního procesu do třídy CommonSync pomocí metody
terminate s parametrem true – synchronizace se zdařila, nebo false – během exportní fáze se
vyskytla chyba. Volání při fázi export jsou podrobně rozkreslena v obrázku 5.3. Všimněme si,
že v diagramu není vůbec zachycen objekt třídy ContactSync, který se na této fázi nepodílí.
5.2. DATABÁZOVÉ ÚLOŽIŠTĚ
43
Obrázek 5.2: Sekvenční diagram fáze import
Obrázek 5.3: Sekvenční diagram fáze export
5.2
Databázové úložiště
Pro ukládání databázových verzí položek slouží databázový stroj SQLite, který je součástí
jádra Mozilla Thunderbird [13]. Informace o účtech jsou dekomponovány do dvou tabulek.
Tabulka loginInfo obsahuje obecné informace o vzdáleném úložišti, tabulka account zahrnuje
informace o konkrétních účtech namapovaných na složku ve vzdáleném úložišti a na lokální
úložiště. Ke konkrétnímu účtu se pak váží řádky v tabulce sync, která obsahuje informace o
verzích položek. Primárním klíčem této tabulky je dvojice <revId : accountUID>. Pro jeden
účet totiž nesmí existovat více položek se stejným číslem revize. Relační schéma databáze
je na obrázku 5.4.
Heslo k účtu na serveru není uloženo v databázi, v Mozilla Application Frameworku existuje pro hesla speciální podpora skrze password manager. Odtud se heslo získává při každé
synchronizaci. Lokální adresář je v případě synchronizace kontaktů uložen jako URI objektu
nsIAbDirectory – kontejneru pro objekty kontaktů. Při změne názvu adresáře zůstává URI
stejná.
44
KAPITOLA 5. REALIZACE
Obrázek 5.4: Relační databázový model
Nejčastějším dotazem nad databází je při synchronizaci získání poslední verze položky
ve tvaru:
SELECT * FROM sync WHERE itemId = ’abc’ AND accountUID = ’def’
ORDER BY revId DESC LIMIT 1
Proto je nad tabulkou sync vytvořen index přes sloupce <revId, itemId, account>. Chování
databázového stroje SQLite při zpracovávání tohoto dotazu bylo ověřeno nad stovkami řádků
a index uchovávající revId v sestupném řazení vyšel z možných variant jako nejvýhodnější.
5.3
Obsluha IMAP úložiště
Obecný synchronizační modul je navržen tak, aby nezávisel na vrstvě obsluhující vzdálené
úložiště. V této práci je vzdáleným úložištěm IMAP server, takže implementace této vrstvy
je spojovníkem mezi common sync vrstvou a IMAP knihovnou. Třída ImapSync přebírá od
CommonSync parametry (účet, položky k zápisu) a předává je do třídy ImapSyncController,
která zajišťuje obsluhu IMAP klienta uvnitř knihovny. ImapSync obsahuje metody lock,
import a export, všechny slouží pouze k vyvolání příslušných částí obsluhy IMAP klienta.
ImapSyncController obsahuje řadu atributů (vnořených objektů), které vyvolávají akce v
klientovi. Pomocí callbacků, které jsou součástí atributů se běh aplikace vrátí zpět do místa,
odkud se příkaz klientovi posílal.
5.3.1
Posloupnost IMAP příkazů
Požadovaného sledu příkazů při importní a exportní fázi je dosaženo přes sekvenci callbacků.
Pro obecné použití je vytvořena initialSequence, která obsahuje navázání spojení se serverem
a příkaz LOGIN, a disconnectSequence obsahující příkazy EXAMINE a LOGOUT. Díky příkazu EXAMINE ještě před odpojením je možné modifikovat záznam o účtu v databázi tak,
5.3. OBSLUHA IMAP ÚLOŽIŠTĚ
45
aby zde byly aktuální údaje o počtu existujících položek ve vzdáleném úložišti (EXISTING)
a NEXTUID. Dále jsou pak vytvořeny importSequence a exportSequence. Sled příkazů v
jednotlivých sekvencích je následující.
initialSequence
importSequence
exportSequence
disconnectSequence
connect, LOGIN
SELECT, UID FETCH (hlavičky zpráv), UID FETCH (celé zprávy)
APPEND, UID COPY, UID STORE, EXPUNGE
EXAMINE, LOGOUT
Sekvenční diagramy znázorňující postup volání příkazů do IMAP knihovny v initial,
import a export sekvenci jsou na obrázcích B.3, B.4 a B.5 v příloze této práce. Všechna
volání jsou asynchronní, proto v diagramech nezachycuji životnost objektu. Metodám uvnitř
IMAP knihovny je znázorněno předání prostředí přes scope.
5.3.2
Struktura obsluhy volání IMAP příkazu
Struktura objektu pro volání konkrétního příkazu vypadá následovně. V metodě command
se vždy zavolá příkaz v IMAP klientu s patřičnými parametry (zde název složky, která
má být vybrána), metody okay a fail jsou callbacky, které jsou zavolány z klienta po příchodu a vyhodnocení odpovědi od serveru. Všimněme si přiřazení scope.current = this;
v řádku 3. V případě, že se vybrání složky podaří, běh aplikace se vrátí do callbacku okay
a rozhoduje se, kam se bude běh programu odebírat dál (popsáno v dalším odstavci), v
případě neúspěchu se vrátí do callbacku fail. ImapSyncController se tak odpojí od serveru
a zavolá ukončení synchronizace (řádky 19 a 20).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
select : {
command : function(scope) {
scope.current = this;
scope.client.select(scope.account.folderStr);
},
okay : function(scope, response) {
if (response.nextUID == scope.account.nextUID
&& response.existingItems == scope.account.existingItems ) {
scope.runDisconnect();
var incommingItems = {changed: "false", items: new Object()};
scope.syncScope.callMakeSyncTable(scope.syncScope, incommingItems);
}
else {
scope.importSequence.fetchUuids.command(scope);
}
},
fail : function(scope, response) {
printOutput(’Select failed’);
scope.runDisconnect();
scope.syncScope.termination(false);
}
}
46
KAPITOLA 5. REALIZACE
Při fázi import je volána nejprve úvodní sekvence příkazů (initialSequence), na níž naváže
importSequence. Z importSequence lze po každém příkazu vystoupit (a ukončit fázi import),
pakliže není nutné načítat další podrobnosti o zprávách. Toto je implementováno dle obrázku
4.2. Ukončení importSequence před vykonáním celého sledu příkazů je realizováno pomocí
podmínek v okay callbacích jednotlivých příkazů.
Opuštění fáze import
Předčasné ukončení sekvence příkazů je ilustrováno také v předchozí ukázce objektu select.
V okay callbacku na řádku 7 je podmínka na rovnost parametrů UIDNEXT a EXISTING
z odpovědi serveru (aktuální) a z databáze (předchozí synchronizace). V případě, že se tyto
parametry rovnají, ukončíme běh importSequence. IMAPSyncController má přes atribut
syncScope k dispozici metody z CommonSync, takže vystoupení ze sledu příkazů se děje
zavoláním scope.syncScope.callMakeSyncTable (řádek 11). V parametrech volání je uvedeno
scope.syncScope. To proto, aby instance CommonSync měla opět k dispozici všechny svoje
atributy. Druhým parametrem je nově vytvořený objekt incommingItems, který obsahuje
atribut changed nastavený na false. Pomocí incommingItems se do obecného jádra vrací
seznam načtených položek. Atribut changed slouží k rozlišení situace, kdy ve vzdáleném
úložišti nebyly vykonány změny (incommingItems.items je prázdný, protože položky nebyly
získávány) a kdy byly vykonány změny a incommingItems.items je prázdný proto, že byly
všechny položky smazány. Obsahuje-li přijímaná položka přílohu, je tato uložena do profilového adresáře do podsložky „ExtBrainSync“ a odkaz na tento soubor je předán společně
s obsahem položky dále do synchronizačního jádra.
Export fáze
Při fázi export sled sekvencí příkazů závisí na obsahu polí objectsToExport a objectsToDelete. Pro zjednodušení obsluh volání příkazů se položky, jejichž verze mají být zapsány, a
pro které zároveň mají být předchozí verze přesunuty, kopírují z objectsToExport do objectsToDelete ve třídě IMAPSync v metodě export. Jsou-li obě pole prázdná, exportní fáze
je ukončena bez volání obsluhy IMAP klienta. Je-li objectsToExport neprázdné pole, je vyvolána nejprve initialSequence, poté exportSequence. Mezi sekvencemi se přechází pomocí
konstruktů v callbacích podobných těm, které jsou popsány v předchozím odstavci. Sled
příkazů je přesnou implementací stavového diagramu v obrázku 4.5. Po úspěšném vykonání
všech potřebných IMAP příkazů se běh programu vrací zpět do instance třídy CommonSync
zavoláním scope.syncScope.termination(true).
5.3.3
Zamykání vzdáleného úložiště
Zamykání vzdáleného úložiště před provedením synchronizace je také v režii tříd IMAPSync
a IMAPSyncController. Volání požadované sekvence příkazů (APPEND zámku a následný
FETCH) je provedeno pomocí sekvencí s callbacky stejně jako je tomu ve fázích import a
export.
Pokud se během synchronizace vyskytne závažná chyba, například se ztratí připojení k
serveru, zámek není možné z úložiště odstranit a to tak zůstává trvale zamčené. Proto pokud
5.4. SYNCHRONIZAČNÍ MODUL KONTAKTŮ
47
při další synchronizaci klient zjistí, že je zamčeno, nabídne uživateli možnost výběru. Buď
může tento fakt přijmout a přerušit synchronizaci, nebo, pokud například víme, že zámek ve
složce zůstal díky chybě, zamčení obejít a pokračovat v synchronizaci dále. V obou případech
aplikace před ukončením ze složky odstraní pouze svůj zámek. Zámek obsahuje informace o
datu, času a v předmětu název počítače a profilu v Thunderbirdu, ze kterého byl odeslán.
„Zaseknutý“ zámek může uživatel odstranit v e-mailovém klientu jednoduše odstraněním
zprávy se zámkem.
5.3.4
IMAP knihovna
V IMAP knihovně implementované Petrem Machem bylo provedeno několik změn. Do klienta
byly přidány příkazy EXAMINE, UID FETCH, UID COPY, UID STORE a EXPUNGE.
Třída odesílající data do socketu MozExtbrainToolkit byla upravena tak, aby podporovala
i znaky mimo ASCII. Dále byla rozšířena třída IMAPParser tak, aby dokázala převádět a
parsovat příchozí data zakódovaná v quoted printable formátu.
5.4
5.4.1
Synchronizační modul kontaktů
Implementace
Rozšiřující modul k synchronizaci kontaktů je implementován třídou ContactSynchronization, která tvoří items layer. Tato třída obsahuje metody pro manipulaci s položkami
makeSyncTable, initialItemsHandling, createItem, deleteItem, acceptChange, handleCollision a další 2 metody na serializaci a deserializaci položek – serialize, deserialize. Třída
je implementací rozhraní ItemSync. Stejně je to zachyceno i v class diagramu na obrázku
5.1.
Za zvláštní zmínku stojí metoda initialItemsHandling, jejíž význam není možná zcela
zřejmý. Metoda je volána v situaci, kdy byla vytvořena nová lokální položka. Během serializace je položce přiřazeno UUID, tento identifikátor je ale nutné uložit přímo do objektu
položky, abychom ji rozlišili při další synchronizaci. Toto zpětné uložení už ale serializace
nezajišťuje a proto musíme před exportem nových položek serializovaná data včetně nově
vytvořeného identifikátoru deserializovat zpět do objektu položky.
5.4.2
Definice formátu obsahu přenášených zpráv
Těla přenášených zpráv při synchronizaci kontaktů mají podobu textové reprezentace JSON
objektů [14]. Pro bezchybnou synchronizaci je nutné definovat přesný tvar objektů v tomto
kontejneru.
JSON obsahuje objekty ve tvaru <atribut : element>, kde element může mít tři různé
typy: string, pole objektů, objekt. Je-li element typu objekt, skládá se ze seznamu subatributů ve tvaru <subatribut : string>. Kontaktní synchronizační modul zná atributy
uvedené v tabulce 5.1. Kromě uvedených subatributů obsahuje každý element typu objekt v
JSONu ještě pomocné subatributy sync a primary. Primary je použito v OS Android pro vyznačení primární položky daného atributu, je typu boolean. Existuje-li například pro jeden
48
KAPITOLA 5. REALIZACE
kontakt více telefonních čísel, můžeme zvolit, které bude upřednostňováno. Subatribut sync
má formát UUID a slouží jako identifikátor elementu. Elementy mohou být do JSONu skládány v různém pořadí a právě sync slouží k tomu, abychom při synchronizaci mohli srovnat
odpovídající si elementy k sobě a zjistit jejich změny. Při řešení kolizí je pomocí subatributu
sync možné identifikovat elementy a odlišit tak situaci, kdy byl jeden element změněn od
situace, kdy byl vytvořen nový. (V prvním případě má řešením kolize být změna elementu,
ve druhé zřetězení těchto elementů.) Ukázka, jak vypadá kontakt se všemi podporovanými
atributy v JSON podobě je v tabulce B.1.
V tabulce 5.1 jsou uvedené i podporované řetězce v subatributech type. Tato množina
je omezená, jedná se o řetězce nativně podporované v OS Android. Je-li jako typ elementu
zvoleno „custom“ znamená to, že v elementu je obsažen subatribut „label“, který obsahuje
uživatelem zadaný vlastní typ elementu. Takto lze vytvořit například událost typu svátek:
event": [{"type":"custom", "label": "svátek", "value": "0000-11-04", "sync":
"ccb515f3-2d80-498c-9ae6-b256e9ee93e8", "primary": "false"}
5.4.3
Serializace a deserializace kontaktů
Přeměna položek z objektů nsIAbCard do podoby JSON se provádí v metodě exportContactProperties procházením přes všechny defaultní a přidané atributy kontaktů. Kromě přidaných atributů přímo přístupných uživateli skrze grafické uživatelské rozhraní je ale i několik
atributů „skrytých“. Synchronizace totiž musí pasivně podporovat i atributy, které Thunderbird ani s nově přidanými atributy nezná. Představit si to lze například na údajích o
společnosti, kde osoba v kontaktu pracuje. Tyto údaje jsou v Thunderbirdu a v OS Android
shrnuty jen na tyto tři: název společnosti, oddělení, funkce. Některá jiná platforma, která
bude v budoucnu do synchronizace zapojena, ale může tyto informace rozšiřovat například
o číslo kanceláře apod. O takovéto informace nesmíme během synchronizace přijít, jak by se
to stávalo pouhým uložením „známých“ atributů do objektu nsIAbCard a jejich pozdějším
vytažení zpět do JSONu. I tyto pro synchronizační modul neznámé atributy musejí být uloženy společně s ostatními tak, abychom je při dalším exportu z objektu, dokázali složit do
původní podoby. Uživatel k těmto atributům logicky má přístup jen v platformě, která tyto
typy „aktivně“ podporuje, tzv. zobrazuje jejich hodnoty v GUI a umožňuje jejich editaci.
Při každém importu (zápisu obsahu JSONu do objektu nsIAbCard) se do speciálních
properties uloží v textové podobě i všechny elementy z JSONu. Při dalším exportu (serializaci) se tyto původní elementy vytáhnou a provede se sloučení původních elementů s nově
exportovanými atributy. Tím je zajištěno, že v nově vyexportovaných elementech nebudou
chybět i subatributy, které nejsou podporovány. Toto slučování probíhá s využitím sync
subatributů v každém elementu.
5.4.4
Chyba v jádru Thunderbirdu
Během vývoje byla objevena a reportována chyba v jádru aplikace Thunderbird. Je-li ke
kontaktu přiřazena fotografie, vytvoří se její kopie v profilovém adresáři aplikace. Po odstranění kontaktu ale soubor s fotografií v adresáři zůstává a zbytečně tak zabírá místo na
5.4. SYNCHRONIZAČNÍ MODUL KONTAKTŮ
atribut
uuid
displayName
name
typ
string
string
object
phone
array
email
array
urls
array
event
array
organization
array
im
array
subatribut
givenName
familyName
displayName
type
value
type
value
type
value
type
value
company
department
title
type
type
value
protocol
sipAddress
array
addresses
array
nickname
array
type
value
type
streetAddress
neighborhood
city
region
postalCode
country
type
array
array
value
photoName
note
photo
note
typ možnosti
home, mobile, work, fax_work,
fax_home, pager, other, callback,
car, company_main, isdn, main,
other_fax, radio, telex, tty_ttd,
work mobile, work_pager, assistant,
mms, custom
home, work, mobile, other, custom
home, work, mobile, other, custom
birthday, anniversary, custom
work, other, custom
home, work, other, custom
aim, msn, yahoo, skype, qq, googleTalk, icq, jabber, netmeeting, custom
home, work, other, custom
home, work, other, custom
default,
other_name,
maiden_name, short_name, initials,
custom
Tabulka 5.1: JSON atributy
49
50
KAPITOLA 5. REALIZACE
disku. Fotografie, které jsou přenášeny v rámci synchronizace jsou uloženy také v profilovém adresáři aplikace ve složce „ExtBrainSync“. Aby nedocházelo k plýtvání místem, je v
možnostech zásuvného modulu přidáno tlačítko na vyčištění této složky, které odstraní fotografie navázané na již neexistující kontakty. Při změně fotografie u kontaktu je případná
stará verze z toho adresáře odstraněna ihned.
5.4.5
Řešení kolizních situací
Kolizní situace jsou v případě kontaktů řešeny zobrazením okna shrnujícího všechny verze
kontaktu. V tomto okně uživatel vybere podobu atributů tak, jak je chce zahrnout do
výsledné položky této kolize. Při zobrazování atributů je aplikován algoritmus trojcestného
slučování (viz. jeho popis v podkapitole Princip synchronizace). Algoritmus prochází přes
hodnoty v atributech položky, zvýrazňuje shodné verze a na základě těchto shod předvybírá
hodnoty do výsledné verze. Samotný výběr hodnot je ale na uživateli. Zeleným zvýrazněním
je ukázáno, že kolize v atributu byla vyřešena, červeně pak situace, kdy jsou všechny tři
verze rozdílné a verzi položky musí zvolit uživatel.
5.5
5.5.1
Grafické uživatelské rozhraní
Rozšíření atributů kontaktu
Okno pro editaci kontaktů se skládá z několika karet obsahujících vždy ovládací prvky k
editaci podobných typů položek. V tomto okně je nově karta s názvem „Instant messaging“
obsahující informace o IM a SIP účtech k danému kontaktu. V případě přidání typů k
atributům je před textbox pro zadání hodnoty atributu vytvořen menulist, což je vstupní
prvek typu „roleta“, ve kterém uživatel vybere z předem definovaných řetězců typů.
Zde je místo pro možný další rozvoj aplikace. U typu atributu „custom“ je skutečný
typ jako uživatelem zadaný vlastní řetězec uložen v atributu „label“. Tento atribut není
v této verzi synchronizačního modulu uživateli přístupný. Pro jeho zpřístupnění je nutný
větší zásah do GUI okna pro editaci kontaktů (je možné přeuspořádání ovládacích prvků,
zobrazení vyskakovacího okna pro zadání konkrétné hodnoty atd.).
Ukládání položek po uzavření editačního okna se i v jádru Thunderbirdu děje průchodem přes předem definované pole známých atributů a uložení jejich hodnot do objektu
nsIAbCard. Uložení přidaných atributů je provedeno stejně. Názvy přidaných atributů jsou
uloženy v souboru attributes.js. Při tvorbě grafického rozhraní byla použita příručka jazyka
XUL z [15]. Okno pro editaci kontaktů je ukázáno na obrázku 5.5.
5.5.2
Wizard na tvorbu účtů
Před samotnou synchronizací je nutné vytvořit účet se všemi potřebnými údaji o serveru,
lokální a vzdálené složce. Protože je důležité mít jistotu, že bylo zadáno správné uživatelské
jméno a heslo k serveru, zda tento server existuje atd., byl tento účel vytvořen průvodce
vytvořením účtu. Průvodce je spuštěn pravým kliknutím na složku kontaktů v adresáři a
5.5. GRAFICKÉ UŽIVATELSKÉ ROZHRANÍ
51
Obrázek 5.5: Okno pro editaci kontaktů s rozšířenými atributy
zvolením „Add ExtBrain Sync account“. Průvodci pak uživatel zadává přihlašovací údaje k
serveru, tyto informace jsou uloženy v databázi v tabulce loginInfo, a tak je při vytváření
více účtů namapovaných na složky na jednom serveru nemusí zadávat opakovaně. Průvodce
přidáním účtu se pak pokusí k serveru přihlásit a získat odtud seznam všech složek. Z nich
uživatel vybírá, nebo může zadat název nové složku, která je po potvrzení vytvořena (včetně
podsložky „Deleted“). Tím je ošetřeno, že složka v nově zadaném účtu skutečně existuje a
účet má platná přihlašovací data.
5.5.3
Obsluha synchronizace
Kontextové menu na složku kontaktů v adresáři má dvě různé podoby. Je-li na složku zaregistrován synchronizační účet, zobrazují se volby „Start sync“ a „Remove ExtBrain Sync
account“, není-li složka v seznamu účtů, zobrazuje se „Add ExtBrain Sync account“. Pro
spolehlivou synchronizaci je nutné zajistit, aby složka, na níž je namapován synchronizační
účet existovala. Již bylo zmíněno, že v databázi je lokální složka uložena jako URI nsIAbDirectory, změna názvu složky tedy synchronizaci nerozbije. Při odstranění složky se odstraní
účet i všechna historická data o synchronizacích tohoto účtu.
Synchronizace složky kontaktů se spouští z kontextového menu příkazem „Start sync“
(viz obrázek C.3). Po jeho vyvolání se zobrazí okno syncLog.xul (viz obrázek 5.6) obsahující
informace o složce a serveru, kam se lokální adresář sychronizuje, je zde i místo pro výpis
aktuálně prováděných operací včetně případných chyb. Při vyvolání synchronizace se pro
lepší user experience (např. při dlouhých prodlevách při načítání zpráv) v tomto okně deaktivuje tlačítko „OK“, které je aktivováno po skončení synchronizace, nebo při závažné chybě
vedoucí k nemožnosti synchronizaci dokončit.
52
KAPITOLA 5. REALIZACE
Obrázek 5.6: Okno informující o průběhu synchronizace
Kapitola 6
Testování
V průběhu vývoje bylo autorem této práce prováděno funkční testování. Na počátku vývoje
byla funkčnost serializace a deserializace rozšířených kontaktních atributů ověřována přes
modul pro synchronizaci kontaktů přes složku na lokálním disku. Tento modul byl posléze
pro komplexnost synchronizačních procesů z aplikace odstraněn. Funkčnost obecného synchronizačního modulu (knihovny) byla ověřena přes modul k synchronizaci kontaktů. Ten
lze testovat jednak posíláním dat z několika profilů aplikace Mozilla Thunderbird a proti
ExtBrain synchronizační aplikaci pro operační systém Android, kterou vyvinul v rámci diplomové práce Ing. Luboš Hilgert [16].
Po dokončení vývoje byl synchronizační modul testován vedoucím práce a okruhem testerů sestávajího se z bývalých vývojářů projektu ExtBrain. Testování synchronizačního modulu bylo prováděno v aplikaci Mozilla Thunderbird ve verzích 10, 11 a 12. Přestože zásuvný
modul závisí pouze na hostitelské aplikaci a měl by se v různých operačních systémech chovat stejně, byl otestován v operačních systémech Microsoft Windows XP, Vista a 7 a v Linux
Ubuntu 11.
Synchronizace byla ověřena pro následující IMAP servery:
∙ imap.feld.cvut.cz,
∙ imap.gmail.com,
∙ imap.aol.com,
∙ imap.mail.yahoo.com.
Některé servery bohužel nejsou implementované podle RFC 3501 a tak například nepodporují vícenásobné vnořování složek (imap.centrum.cz, imap.seznam.cz) nebo před název
uživatelem vytvořené složky přidávají vlastní řetězec (imap.seznam.cz). Podpora pro tyto
servery je tedy omezená. Funkčnost závisí na tom, zdali se podaří vytvořit synchronizační
složku a její podsložku s názvem „Deleted“.
Charakter vytvořené práce se během vývoje změnil ze samostatné aplikace spíše ke knihovní aplikaci, která je v současné době portována do většího projektu ExtBrain Communicator kolegou Bc. Davidem Jirovcem. Po dohodě s vedoucím práce tedy nebyly prováděny
53
54
KAPITOLA 6. TESTOVÁNÍ
speciální testy zaměřující se na uživatelské rozhraní synchronizačního modulu. Funkčnost
modulu je nyní ověřována již během testů při vývoji výše zmiňované aplikace. Uživatelské
rozhraní, které je v aplikaci obsaženo slouží k vytváření účtů a k demonstraci funkčnosti
synchronizace.
Kapitola 7
Závěr
Výsledkem této práce je synchronizační modul v aplikaci Mozilla Thunderbird, který je
možné využít pro synchronizaci jakýchkoli textových informací včetně příloh v binárním
tvaru. Synchronizační modul je obecný a je nezávislý na vzdáleném úložišti, konkrétně je
implementována podpora pro vzdálené úložiště v podobě IMAP serveru. Funkčnost tohoto
modulu je ukázána na vytvořeném zásuvném modulu pro synchronizaci kontaktů ve stejné
hostitelské aplikaci. V práci byl popsán ExtBrain Sync protokol, podle kterého se celá synchronizace řídí. Synchronizační aplikaci podle stejného protokolu implementoval pro OS
Android ve své diplomové práci Ing. Luboš Hilgert. Díky těmto dvěma modulům je tedy
možné synchronizovat kontaktní informace z Thunderbirdu s telefonem. Na práci navazuje
projekt Bc. Davida Jirovce s názvem ExtBrain Communicator, která modul přebírá a implementuje synchronizaci kalendářových dat a poznámek.
Práce naplnila všechny požadavky, po dohodě s vedoucím došlo k jediné úpravě v zadání
a to k ustoupení od rozsáhlejších testů uživatelského rozhraní z důvodu integrace modulu
do většího projektu, které bude mít svoje vlastní uživatelské rozhraní.
7.1
Možná další rozšíření
Na projekt je možné kdykoli navázat implementací modulů pro synchronizaci dalších typů
položek. Dále je možné zabývat se vylepšeními speciálně v těchto ohledech:
Grafické uživatelské rozhraní pro editaci kontaktů V okně pro editaci kontaktů je
staticky zobrazeno několik polí pro zadávání hodnot konkrétních atributů. Ovládací prvky v
tomto okně by mohly být přeuspořádány tak, aby se zobrazovaly vždy jen zadané hodnoty.
Další řádek pro přidávání hodnot by se zobrazil kliknutím na tlačítko „+“. Synchronizační
modul je na toto připraven, počet hodnot pro jeden atribut není omezen.
Dále je zde možnost vytvořit podporu zadávání vlastních štítků pro atributy, jako je
tomu v OS Android. (Např. možnost přidat typ adresy „přechodné bydliště“.)
55
56
KAPITOLA 7. ZÁVĚR
Automatická synchronizace pomocí IMAP push Pro IMAP protokol existuje rozšíření s názvem push-email, který zajišťuje odeslání zpráv z IMAP serveru na klienta ihned po
přijetí zprávy serverem, bez nutnosti opakovaného dotazování klientem na stav serveru. Tuto
technologii by bylo možné přidat do synchronizačního modulu tak, aby se informace ihned
po změně a uložení na server replikovaly i na další připojené klienty. S touto technologií
pracuje synchronizační standard SyncML.
Literatura
[1] NOVOTNÝ, Tomáš. ExtBrain – to simplify everyday tasks [online]. [cit. 18. 11. 2011].
Dostupné z: http://extbrain.felk.cvut.cz
[2] Zimbra Email and Collaboration Server [online]. 2012 [cit. 5. 11. 2011].
Dostupné z: http://www.zimbra.com/products/email-server.html
[3] KHANNA, Sanjeev, Keshav KUNAL, a Benjamin PIERCE: A Formal Investigation of
Diff3. [online]. [2007] [cit. 14. 1. 2012].
Dostupné z: http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf
[4] CRISPIN, M. RFC 3501 - INTERNET MESSAGE ACCESS PROTOCOL - VERSION
4rev1 [online]. 2003 [cit. 10. 12. 2011].
Dostupné z: http://www.faqs.org/rfcs/rfc3501.html
[5] CROCKER, David H. RFC 822 - STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES [online]. August 13, 1982 [cit. 10. 12. 2011].
Dostupné z: http://www.ietf.org/rfc/rfc0822.txt
c 2011
[6] PETERKA, Jiří. RFC 822. Jiří Peterka: archiv článků a přednášek [online]. ○
[cit. 14. 1. 2012].
Dostupné z: http://www.earchiv.cz/a94/a435c110.php3
[7] BOSSWELL, David, Brian KING, Ian OESCHGER aj. Creating Applications with Mozilla. First edition. Sebastopol, CA, USA: O’Reilly Media, 2002.
[8] NYMAN, Robert. How to develop a Firefox extension [online]. 2009 [cit. 7. 10. 2011].
Dostupné
z:
http://blog.mozilla.org/addons/2009/01/28/
how-to-develop-a-firefox-extension/
c 2005-2012. [cit. 5. 3. 2012].
[9] Mozilla. Mozilla Developer Network [online]. ○
Dostupné z: https://developer.mozilla.org/en/
[10] ContactsContract.CommonDataKinds. Android Developers [online]. 2012 [cit.
14. 1. 2012].
Dostupné
z:
http://developer.android.com/reference/android/provider/
ContactsContract.CommonDataKinds.html
[11] SMARR, Joseph. Portable Contacts 1.0 Draft C [online]. August 5, 2008 [cit.
12. 2. 2012].
Dostupné z: http://portablecontacts.net/draft-spec.html
57
58
LITERATURA
[12] Introducing JSON. [online] [cit. 12. 2. 2012].
Dostupné z: http://www.json.org
[13] SQLite - Documentation [online]. [cit. 12. 2. 2012].
Dostupné z: http://www.sqlite.org/docs.html
[14] CROCKFORD, Douglas. The application/json Media Type for JavaScript Object Notation (JSON) [online]. July 2006 [cit. 12. 2. 2012].
Dostupné z: http://www.ietf.org/rfc/rfc4627
[15] Mozilla Developer Network. XUL reference [online]. 26 April 2010 [cit. 5. 3. 2012].
Dostupné z: https://developer.mozilla.org/en/XUL_Reference
[16] HILGERT, Luboš. Modul pro správu informací pro Android. Praha, 2012. Diplomová
práce. České vysoké učení technické v Praze.
Příloha A
Seznam použitých zkratek
API Application Programming Interface
DOM Document Object Model
IM Instant Messaging
IMAP Internet Message Access Protocol
JSON JavaScript Object Notation
OS Operating System
SIP Session Initiation Protocol
TH Thunderbird
URI Uniform Resource Identifier
UUID Universally Unique IDentifier
XUL XML User Interface Language
59
60
PŘÍLOHA A. SEZNAM POUŽITÝCH ZKRATEK
Příloha B
Obrázky a diagramy
Obrázek B.1: Návrh okna pro editaci kontaktů
61
62
PŘÍLOHA B. OBRÁZKY A DIAGRAMY
Obrázek B.2: Sekvenční diagram všech fází synchronizace
63
Obrázek B.3: Volání IMAP příkazů v initialSequence
64
PŘÍLOHA B. OBRÁZKY A DIAGRAMY
Obrázek B.4: Volání IMAP příkazů v importSequence
65
Obrázek B.5: Volání IMAP příkazů v exportSequence
66
PŘÍLOHA B. OBRÁZKY A DIAGRAMY
{"displayName": "Karel Poláček",
"uuid": "456af2dd-0783-44f6-9984-2d9d09baf41b",
"name": {"familyName": "Poláček", "givenName": "Karel", "displayName": "Karel Poláček", "sync": "7497ada0-ffa2-42b9-be96-38fba9d56d88", "primary": "false"},
"event": [{"sync": "ccb515f3-2d80-498c-9ae6-b256e9ee93e8", "type": "birthday", "value":
"1893-03-22", "primary": "false"}],
"email": [{"sync": "9fee2628-76f5-43f4-b7d7-b11bbe9c01cf", "type": "home", "value": "[email protected]", "primary": "false"}],
"phone": [{"sync": "9c258986-ef2f-4ef2-a80d-401107267ab8",
"type": "work", "primary": "false"}],
"value":
"222-323-983",
"urls": [{"sync": "752921fb-ced8-4563-95b0-bd91c7dcf3d9", "type": "profile", "value":
"http://cs.wikipedia.org/wiki/Karel_Polacek", "primary": "false"}],
"im":
[{"sync":
"adccda29-cf68-4712-bae3-3749ab2dea99",
"value":
"[email protected]", "protocol": "googleTalk", "type": "home", "primary":
"false"}],
"sipAddress": [{"sync": "0d7211cd-5be2-4c0f-ad53-ec3586f20ce4",
[email protected]", "type": "home", "primary": "false"}],
"value":
"ka-
"addresses": [{"sync": "4dafb46f-8ba4-4852-b945-ec938f166595", "region": "Praha", "streetAddress": "Koněvova 343", "postalCode": "11022", "primary": "false", "neighborhood": "Žižkov", "type": "home", "city": "Praha", "country": "Česká republika"}],
"organization": [{"sync": "03800363-8964-44c9-b419-bc29cd4787f2", "title": "sloupkař",
"type": "work", "department": "denní tisk", "primary": "false", "company": "Lidové noviny"}],
"note": [{"sync": "99972fd1-7e27-4308-9375-f51b76f42a00", "note": "Má 4 bratry: Arnošta,
Kamila, Ludvíka a Zdeňka", "primary": "false"}],
"nickname": [{"sync": "f42e1dbc-73a3-4dac-9eff-716f445c8178", "value": "Polič", "type":
"default", "primary": "false"}],
"photo": [{"sync": "1d3ff9db-3b4e-4c9b-ac85-9c96fe07667d", "photoName": "karel.png",
"primary": "true"}]}
Tabulka B.1: Kontakt v JSON podobě se všemi podporovanými atributy
Příloha C
Instalační příručka
Pro správnou činnost doplňku je doporučováno používat Mozilla Thunderbird ve verzi
11.0.1 (v době psaní této příručky nejnovější verze). Zásuvný modul se instaluje ze souboru ExtBrainSync.xpi, který najdeme na přiloženém CD.
C.1
Instalace
1. Otevření Nástroje -> Správce doplňků v aplikaci Mozilla Thunderbird.
2. Přetažení (drag&drop) instalačního souboru ExtBrainSync.xpi do tohoto správce.
3. Potvrzení instalace.
4. Restart aplikace Thunderbird.
C.2
Vytvoření účtu
1. Kliknutím pravým tlačítkem na složku kontaktů v adresáři otevřete kontextové menu
a zvolte „Add ExtBrain Sync accout“, otevře se průvodce vytvořením účtu.
2. Klikněte na „Create new“. Zadejte přihlašovací údaje k IMAP serveru, jeho adresu a
typ zabezpečení (SSL nebo TLS) a potvrďte kliknutím na „Další“.
3. Vyberte složku, kam chcete kontakty synchronizovat, nebo zadejte název nové složky.
4. Účet se vytvoří kliknutím na „Další“.
V případě, že jste již zadali přihlašovací údaje k IMAP serveru, nemusíte je při vytváření účtu k jiné složce zadávat znovu, ale ve druhém kroku lze vybrat ze seznamu již
registrovaných serverů (viz obrázek C.1).
Seznam všech vytvořených účtů můžete zkontrolovat v okně „Možnosti ExtBrain Sync“.
Toto okno se otevírá ve Správci doplňků. V možnostech najdete také tlačítko na vyčištění
složky s fotografiemi kontaktů.
67
68
PŘÍLOHA C. INSTALAČNÍ PŘÍRUČKA
Obrázek C.1: Úvodní okno průvodce pro vytváření účtů
Obrázek C.2: Okno se seznamem složek na serveru
C.3. SPUŠTĚNÍ SYNCHRONIZACE
C.3
69
Spuštění synchronizace
Synchronizace se spouští kliknutím na „Start sync“ v kontextovém menu složky kontaktů. Po
spuštění se otevře okno s informacemi o synchronizovaném účtu a probíhajících operacích.
Po dokončení synchronizace zavřete toto okno tlačítkem „OK“.
Obrázek C.3: Spuštění synchronizace
70
PŘÍLOHA C. INSTALAČNÍ PŘÍRUČKA
Příloha D
Obsah přiloženého CD
ExtBrainSync
text
ExtBrainSync.xpi
readme.txt
<DIR>
<DIR>
projektový adresář se zdrojovými soubory
adresář s textem této práce (zdrojové kódy LATEXu i pdf)
instalační soubor zásuvného modulu
instalační informace
71

Podobné dokumenty

Implementace protokolu XMPP v JavaScriptu

Implementace protokolu XMPP v JavaScriptu Prohlašuji, že jsem práci vypracoval samostatně a použil jsem pouze podklady uvedené v přiloženém seznamu. Nemám závažný důvod proti užitı́ tohoto školnı́ho dı́la ve smyslu §60 Zák...

Více

P°íloha E Instala£ní a uºivatelská p°íru£ka

P°íloha E Instala£ní a uºivatelská p°íru£ka tla£ítko na uloºení pravidel, tla£ítko pro smazání aktuálního výb¥ru, moºnost p°epnou li²tu do horního rohu a kone£n¥ zru²ení výb¥ru. Po najetí kurzorem nad n¥jaký prvek se tento prvek ohrani£í rám...

Více

Modul pro £tení zpráv pro Android

Modul pro £tení zpráv pro Android Rád bych pod¥koval vedoucímu práce Ing. Tomá²i Novotnému za ochotu a cenné rady poskytnuté p°i vypracovávání této bakalá°ské práce. Dále bych cht¥l pod¥kovat své rodin¥ za podporu p°i studiu.

Více

Rozs20 s19 r20 ren19 ExtBrain Communicatoru o dals20 s19

Rozs20 s19 r20 ren19 ExtBrain Communicatoru o dals20 s19 volánı́ XPCOM objektů, volánı́ obsluhy událostı́, atd. Usnadňuje tak programátorovi integraci nových funkcionalit do Mozilly. Pro skriptovánı́ pod frameworkem XPFE je použı́ván JavaScript...

Více

České Vysoké Učení Technické v Praze Fakulta

České Vysoké Učení Technické v Praze Fakulta Každý vyhledávací modul vyhledává v jednom zdroji informací. Tyto zdroje se mohou velmi lišit, co do typu poskytovaných informací, tak do způsobu jejich uložení, formátu, tak i způsobu jejich získá...

Více