Laureline's Wiki

Laureline's Wiki

Gestion des Volumes

Gestion des Volumes

La gestion des volumes utilise l'api 7zip-JavaBindings. Cette api permet d'interragir avec 7zip, logiciel gratuit, permettant de décompresser et compresser beaucoup de format d'archives actuels, tel que rar, 7zip, zip, bzip2, etc. 7zip est par ailleurs disponible sur tous les Systèmes d'exploitations courants. 7zip-JavaBindings est aussi disponible sur les systèmes d'exploitation courants (windows, linux, mac osx et arm).

Ce choix a été motivé par l'existance même de cette api. En effet, le fait de devoir potentiellement traiter plusieurs types d'archives aurait été compliqué à implémenter en java et pas nécessairement supporté par java de base.

C'était un choix risqué à prendre, car personne dans le groupe n'avait utilisé 7zip-JavaBindings auparavant. Nous ne savions donc pas comment l'api allait réagir, si elle avait des bugs ou pas, etc.

7zip-JavaBindings fonctionne en mode 1-1, c'est à dire que lors de l'extraction d'une archive, l'on doit appeler systématiquement la fonction extractSlow() qui permet d'extraire un seul fichier de l'archive à la fois. Cette fonction est lente, d'où son nom, mais comparé à l'autre solution, qui se comporte comme une approche c++, cette solution parraissait la plus simple. Après quelques tests il s'est avéré que cette fonction n'est pas si lente que cela. A cause de ce comportement de 7zip-Javabindings, chaque archive doit être extraite via une boucle, qui permet de traverser l'entier des fichiers présents dans l'archive.

Afin d'éviter de trop surcharger l'application, qui peut tourner sur un pc plus lent que les nôtres, un système de Lazy loading a été mis en place afin de ne pouvoir charger qu'une seule partie d'un volume et non l'entier. Ce système prend en paramètre une certaine plage de page à charger et permet de charger ces dernières uniquement. Au fur et à mesure de l'avancement dans les pages, les suivantes peuvent être chargées dynamiquement.

L'architecture des volumes se présente comme suit:

<uml> hide empty fields hide empty methods

Interface Volume Volume : getPages(): List<Page> Volume : getMetadata(): VolumeMetadata

Volume <|– LazyVolume LazyVolume : loadPage(int index) LazyVolume : loadPages(int start, int end)

Volume <|– EagerVolume

Volume <|– MutableVolume MutableVolume : createPage(): Page

Volume *- Page :contains

Interface Page Page : getImage(): byte[] Page : setPath() Page : compareTo(Page other): int

Page <|– LazyPage Page <|– EagerPage Page <|– MutablePage MutablePage : getFilename(): String MutablePage : setImage(byte[] i) MutablePage : setFilename(String name)

MutableVolume <.. VolumeWriter :creates

EagerVolume <.. EagerVolumeLoader :creates LazyVolume <.. LazyVolumeLoader :creates

Interface IVolumeLoader IVolumeLoader : load(String path, VolumeMetadata metadata): Volume EagerVolumeLoader –|> IVolumeLoader LazyVolumeLoader –|> IVolumeLoader

Class ImageReader ImageReader : write(byte[] data): int ImageReader : makePage(): Page LazyVolumeLoader …> ImageReader :uses EagerVolumeLoader …> ImageReader :uses

Class “7zip-JavaBindings” as 7jb ImageReader ..> 7jb :uses VolumeWriter …> 7jb :uses LazyVolumeLoader …> 7jb :uses EagerVolumeLoader …> 7jb :uses

Interface IVolumeWriter IVolumeWriter : load(String path): Volume IVolumeWriter : write(String path, Volume volume) IVolumeWriter : createEmpty(): Volume IVolumeWriter : createPage(Volume volume): Page IVolumeWriter : setPageName(Page page, String name) IVolumeWriter : setPageContents(Page page, byte[] content) VolumeWriter –|> IVolumeWriter

</uml>

Comme on peut le voir sur le schéma ci-dessus, les volumes sont composés de pages. Ces dernières sont de type différents selon les différents types de volumes. Un EagerVolume contiendra des EagerPage, un LazyVolume des LazyPage et ainsi de suite. Chaque type de page est légèrement différent d'un autre, car ils ne servent pas les mêmes usages.

Nous pouvons aussi observer que les deux VolumeLoader (Eager et Lazy) utilisent tous-deux la classe ImageReader. Cette dernière fait le lien entre les 7zip-JavaBindings et la librairie. Cette classe est particulièrement utilisée pour récupérer les données de l'archive ouverte. Elle contient notamment la fonction write(byte[] data) qui permet à 7zip d'aller écrire dans ce byte array ce qu'il a lu dans le fichier en extraction (une archive peut évidement contenir plusieurs fichiers). Lors de l'écriture c'est un peu plus compliqué. Le VolumeWriter appèle une fonction 7zip-JavaBindings, qui elle même va appeler une fonction de l'api 7zip. Cette fonction 7zip va ensuite rappeler via un callback la classe StatusCallback (classe privée de VolumeWriter), qui contient les fonctions getStream(int index) et getItemInformation(int index, OutItemFactory<IOutItemZip> outItemFactory). Ces dernières permettent à 7zip de créer le fichier dans l'archive, avec les bonnes permissions, bon chemin, etc.

Petit bémol, en travaillant directement avec l'archive, les ficheirs sont lus dans leur ordre au sein de l'archive. Ceci ne garantit pas du tout le bon ordre des pages d'un volume. En effet si la page 2 est enregistrée avant la 0 et la 1, alors le premier fichier lu sera la page 2 et non la page 0 comme on pourrait s'y attendre. Ceci a dû être traité lors du chargement du volume. Le EagerVolumeLoader chargeant toutes les pages d'un coup, il n'a pas été difficile de trier ses pages une fois chargées en mémoire. Le LazyVolumeLoader permettant de ne charger qu'un certain nombre de pages, ne permet pas de trier aussi facilement les pages. En effet, il suffit que la page 0 soit la dernière, alors les 10 premières pages peuvent être les pages 1 à 10, mais devraient être les pages 0 à 9. Une solution simple serait de charger, trier et réécrire le volume, mais c'est très peu propre et non-performant. Ceci posant un sérieux problème lors du chargement du volume, le chargement en mode Lazy n'a pas été implémenté dans la liseuse (qui devrait dans ce mode demander les pages suivantes à chaque changement de page affichée).