j2me - campus.hesge.chcampus.hesge.ch/daehne/tb/2004/roggojeanchristophetout.pdf · des...

78
Travail de diplôme Roggo Jean-Christophe - 1 - J2ME Développement d’applications Java pour terminaux mobiles

Upload: duongmien

Post on 13-Sep-2018

215 views

Category:

Documents


0 download

TRANSCRIPT

Travail de diplôme Roggo Jean-Christophe

- 1 -

J2ME

Développement d’applications Java pour terminaux mobiles

Travail de diplôme Roggo Jean-Christophe

- 2 -

1. J2ME et l’informatique des terminaux mobiles ............................5

1.1. Les applications embarquées .................................................................. 5 1.1.1. Typologie des applications...................................................................................... 6

1.2. J2ME et les systèmes embarqués............................................................. 7 1.2.1. Tour d’horizon de la technologie J2ME....................................................................... 8

1.2.1.1. Les machines virtuelles ......................................................................................9 1.2.1.2. Les configurations ..........................................................................................11 1.2.1.3. Les profils ....................................................................................................11 1.2.1.4. Les packages optionnels ..................................................................................13 1.2.1.5. La pile JSR 185 JTWI (Java Technology for the Wireless Industry).................................16 1.2.1.6. Les autres API Java pour terminaux embarqués.......................................................17

2. La configuration CLDC......................................................19

2.1. Les limitations de CLDC ...................................................................... 19 2.1.1. Support de la virgule flottante ................................................................................ 19 2.1.2. Internationalisation des applications ....................................................................... 19 2.1.3. Support des propriétés d’environnement.................................................................. 21 2.1.4. Limitations diverses............................................................................................. 21

2.2. La sécurité dans CLDC ....................................................................... 22 2.2.1. Prévérification des fichiers de classe....................................................................... 22 2.2.2. Le modèle de sécurité Sandbox.............................................................................. 23

2.3. Les classes de CLDC ......................................................................... 23 2.3.1. Les classes héritées de J2SE ................................................................................. 23 2.3.2. Les classes spécifiques de CLDC ........................................................................... 24

3. Le profil MIDP ................................................................27

3.1. Le MIDlet ........................................................................................ 27 3.1.1. Cycle de vie d’un MIDlet........................................................................................ 27 3.1.2. L’accès aux attributs du fichier *.jar......................................................................... 29

3.2. L’interface utilisateur........................................................................... 30 3.2.1. Les principes de l’interface utilisateur MIDP .............................................................. 30 3.2.2. Les classes d’affichage ........................................................................................ 31

3.2.2.1. La classe Display ...........................................................................................31 3.2.2.2. La classe Displayable ......................................................................................32 3.2.2.3. La classe Screen ...........................................................................................32 3.2.2.4. La classe Canvas...........................................................................................33

3.2.3. L’interface utilisateur de haut niveau ....................................................................... 34 3.2.3.1. L’interface Choice ..........................................................................................35 3.2.3.2. La classe List................................................................................................36 3.2.3.3. La classe Item...............................................................................................37 3.2.3.4. La classe Form..............................................................................................37 3.2.3.5. La classe ChoiceGroup ....................................................................................38 3.2.3.6. La classe TextField.........................................................................................38 3.2.3.7. La classe DateField ........................................................................................39 3.2.3.8. La classe Gauge ............................................................................................40 3.2.3.9. La classe ImageItem .......................................................................................41 3.2.3.10. La classe StringItem ......................................................................................42 3.2.3.11. La classe TextBox ........................................................................................42 3.2.3.12. La classe Alert .............................................................................................42 3.2.3.13. La classe Ticker ...........................................................................................44

Travail de diplôme Roggo Jean-Christophe

- 3 -

3.2.4. La gestion des évènements ................................................................................... 44 3.2.4.1. La classe Command .......................................................................................44 3.2.4.2. L’interface commandListener .............................................................................45 3.2.4.3. L’interface ItemStateListener..............................................................................46

3.3. Le stockage persistant des données........................................................ 47 3.3.1. Le package RMS ................................................................................................. 47 3.3.2. Le Record Store .................................................................................................. 47

3.3.2.1. La classe RecordStore.....................................................................................48 3.3.2.2. L’interface RecordComparator............................................................................49 3.3.2.3. L’interface RecordFilter ....................................................................................49 3.3.2.4. L’interface RecordEnumeration...........................................................................49 3.3.2.5. L’interface RecordListener ................................................................................50

4. J2ME en pratique ............................................................51

4.1. Les outils ........................................................................................ 51 4.1.1. L’environnement de développement ........................................................................ 51

4.1.1.1. J2ME Wireless Toolkit 2.1.................................................................................52 4.1.2. Le terminal mobile cible........................................................................................ 55

4.1.2.1. Le terminal mobile Sony Ericsson t610..................................................................55 4.1.3. L’outil de transfert de l’application .......................................................................... 56

4.2. L’application CurrencyConverter............................................................. 57 4.2.1. Le client J2ME .................................................................................................... 58 4.2.2. Le serveur PHP ................................................................................................... 60 4.2.3. Le Web service ................................................................................................... 60

5. Conclusion ....................................................................61

Travail de diplôme Roggo Jean-Christophe

- 4 -

Avant-propos

L’objectif de ce dossier est de présenter la technologie Java 2 Micro Edition (J2ME). Cette technologie, proposée par Sun Microsystem, permet de développer des applications pour les terminaux embarqués en utilisant le langage Java. Les trois premières parties de la présente étude fournissent les notions théoriques nécessaires à une compréhension approffondie de la technologie J2ME. La dernière partie, quant à elle, présente un prototype réalisé au cours de cette étude. Un cd rom ainsi que trois documents contenant des exemples pratiques sont annexés. Le cd rom contient tous les fichiers et logiciels nécessaires pour mettre en œuvre les différents exemples pratiques.

Travail de diplôme Roggo Jean-Christophe

- 5 -

Cette première partie débute par une présentation du panorama des applications pour terminaux embarqués. Vous trouverez ensuite une description de la technologie J2ME et de la place qu’elle occupe dans le paysage de la mobilité.

1. J2ME et l’informatique des terminaux mobiles

1.1. Les applications embarquées

Un système embarqué (embedded system), est un système informatique autonome interagissant en temps réel avec le monde physique de manière généralement invisible. Il est constitué de un ou plusieurs processeurs accompagnés de logiciels [DEL02]. Initialement réservés aux grands domaines technologiques classiques comme le spatial, le nucléaire ou l’aéronautique, les systèmes embarqués apparaissent désormais massivement à l’échelle de l’individu et envahissent tous les domaines de sa vie privée et professionnelle : téléphones mobiles, assistants personnels, cartes à puces, appareils multimédias, automobiles, domotique, surveillance médicale, … Le marché des systèmes embarqués est en pleine explosion, puisqu’il représentait 40 milliards d’euros en 2002 et que sa croissance est d’environ 20% par année (Durlacher Research). Les secteurs les plus porteurs sont le transport, le multimédia, la téléphonie, la monétique, la transitique (logistique limitée aux liaisons internes d’une entreprise) et la banque. Les téléphones mobiles et assistants personnels contribuent de manière non négligeable à la croissance du marché des terminaux embarqués. Selon un rapport publié par la société d'étude britannique Canalys, le marché mondial des terminaux mobiles (téléphones mobiles, PDA, Smartphones …) affiche une croissance de 41 % pour le premier trimestre 2004 (par rapport au premier trimestre 2003) [JNE04]. Le tableau présenté ci-dessous illustre ce phénomène de croissance (source Canalys).

Le marché mondial des terminaux mobiles au 1er trimestre 2004

Constructeur Ventes (en millions d'unités) Part de marché

Evolution des ventes (par rapport au premier

trimestre 2003) Nokia 1,67 28,2 % +85 %

PalmOne 0,99 16,8 % -9 % HP 0,57 9,7 % +29 %

RIM 0,37 6,4 % +301 % Fijutsu 0,36 6,1 % +507 %

Motorola 0,31 5,3 % +12 748 % Sony Ericsson 0,26 4,4 % +19 %

Sony 0,20 3,4 % -45 % Dell 0,16 2,7 % -3 %

Siemens 0,08 1,5 % +470 % Autres 0,90 15,5 % +10 % Total 5,93 100 % +41 %

Travail de diplôme Roggo Jean-Christophe

- 6 -

1.1.1. Typologie des applications

Il est intéressant d’établir une typologie des applications destinées aux systèmes embarqués en fonction des différentes architectures [DEL02] (cf Gartner Model):

Les applications locales qui peuvent s’exécuter sur des terminaux sans couverture réseau. Ce sont, par exemple, les jeux autonomes, les calculatrices, les mémo pad, …

Les applications fonctionnant en réseau peer-to-peer qui sont des applications réseau terminal à terminal sans serveur. Ce sont , par exemple, les applications de chat en direct, les jeux en réseau, …

Les applications client-serveur (client léger) qui sont des applications très légères dans lesquelles le terminal côté client a une logique applicative limitée. Ce sont, par exemple, les applications qui mettent en forme du contenu fourni par une application serveur.

Les applications client-serveur intelligentes (client lourd) qui sont les applications dans lesquelles le terminal côté client a plus de logique applicative et de traitement local.

Le tableau ci-dessous présente les types de clients par catégorie d’application.

Catégorie d’application Micronavigateur

(navigateur WAP) J2ME

Application locale Non Oui

Réseau peer-to-peer Non Oui

Application client-serveur (client léger)

Oui Oui

Application client-serveur (client lourd)

Non Oui

[DEL02] Notons que l’on peut également classer les applications par domaine : loisirs, applications métier, applications PIM (Personal Information Manager), application réseau, utilitaires, …

Le domaine des loisirs comprend les jeux autonomes et en réseau.

Les principales applications métier concernent le commerce électronique, la banque, le CRM (Customer Relationship Management) ainsi que la gestion des ressources.

Les applications PIM comprennent les planificateurs, les répertoires d’adresses …

Les applications de connectivité comprennent les clients de messagerie, les gestionnaires de SMS, …

Le domaine des utilitaires comprend les calculatrices, les memos pad, …

Travail de diplôme Roggo Jean-Christophe

- 7 -

1.2. J2ME et les systèmes embarqués

En 1998, Sun Microsystems Laboratories lance le projet de recherche Spotless dont le but est d’adapter le langage Java pour des systèmes limités en ressource et de réaliser une machine virtuelle de petite taille assurant la portabilité. En Juin 1999, Sun présente la nouvelle plate-forme Java 2 Micro Edition (J2ME). Les travaux de standardisation des composants du J2ME débutent en Octobre 1999 [WJS04]. J2ME fait partie de la plate-forme Java 2. Ci-dessous vous trouverez une illustration qui situe la technologie J2ME au sein de la plate-forme Java 2.

[JSU04] Comme l’illustre l’image ci-dessus, la technologie J2SE cible les ordinateurs standards de bureau, la technologie J2EE est destinée aux serveurs et la technologie J2ME est spécialement conçue pour le développement d’applications sur des terminaux mobiles. Sun Microsystems cible donc le marché avec une suite de technologies fondées sur Java qui simplifient le déploiement pour les fabricants de terminaux, les fournisseurs de services et les développeurs d’applications des produits client et embarqués. J2ME s’adresse particulièrement aux terminaux embarqués, comme les téléphones cellulaires, les assistants personnels (PDA), les décodeurs TV numérique, les consoles de jeux, les terminaux de paiement, les systèmes embarqués dans les véhicules, … Ces terminaux sont soumis à certaines contraintes :

Interface utilisateur limitée (clavier, écran tactile)

Affichage limité (taille, couleur)

Peu de mémoire

Connectivité limitée

Alimentation (batterie)

Travail de diplôme Roggo Jean-Christophe

- 8 -

Encombrement et poids faibles

Résistance aux chocs

La présente étude se concentrera plus particulièrement sur les terminaux de type téléphone cellulaire. Ces terminaux spécialisés, aux fonctionnalités limitées, sont généralement dotés de processeurs 32 bits et d’une connectivité réseau.

1.2.1. Tour d’horizon de la technologie J2ME

J2ME offre un certain nombre d’avantages dans le domaine du développement d’applications embarquées. Le premier d’entre eux est la mise à disposition d’outils performants (J2ME Wireless Toolkit) et faciles à utiliser garantissant un développement rapide des applications. Ces outils permettent par exemple de minimiser l’utilisation du terminal dans le cycle de développement en mettant à la disposition du développeur un émulateur de terminal. L’émulateur reproduit fidèlement le comportement d’un terminal, y compris ses performances et son aspect physique. Notons qu’il est primordial que l’émulateur reproduise les mêmes performances qu’un vrai terminal afin de développer des applications parfaitement adaptées aux performances réelles du terminal et non pas à celle de l’ordinateur de bureau effectuant l’émulation. Les outils proposés permettent également un déploiement aisé des applications grâce au mécanisme de packaging. Ces outils seront présentés dans la dernière partie de ce dossier (cf 4). Un autre avantage considérable de la technologie J2ME est qu’elle permet de développer des applications adaptées aux capacités des terminaux en réutilisant des sous-ensembles d’API existantes et en proposant des éléments optionnels. J2ME est une technologie basée sur une architecture modulaire. Les briques de base de la technologie J2ME sont la configuration, le profil et les packages optionnels [DSU04]. Une configuration est une machine virtuelle ainsi qu’un ensemble minimal de classes de base et d’API. Elle spécifie un environnement d’exécution généralisé pour les terminaux embarqués et agit comme plate-forme Java sur le terminal. Un profil est une spécification des API Java définie par l’industrie, utilisée par les fabricants et les développeurs à destination de terminaux spécifiques. Un package optionnel est, comme son nom l’indique, un package qui peut ne pas être implémenté sur un terminal particulier. Les machines virtuelles J2ME et les spécifications d’API de plate-formes spécifiques sont développées en sollicitant les besoins d’entrée par l’initiative du JCP (Java Community Process) de façon à s’assurer que les spécifications répondent aux besoins spécifiques d’une famille ou d’une catégorie de terminaux clients. Une fois une JSR (Java Specification Request) acceptée par l’initiative JCP, la JSR, qui peut être proposée par Sun Microsystems ou par une autre société, crée une machine virtuelle Java et une implémentation de référence API pour la plate-forme J2ME cible.

Travail de diplôme Roggo Jean-Christophe

- 9 -

Ci-dessous quelques exemples de JSR [DSU04]:

JSR 30 pour CLDC (Connected Limited Device Configuration)

JSR 36 pour CDC (Connected Device Configuration)

JSR 37 pour MIDP (Mobile Information Device Profile)

JSR 46 pour Foundation profile

JSR 62 pour Personal profile

JSR 66 pour RMI Profile

La technologie J2ME bénéficie des avantages liés aux autres technologies de la plate-forme Java 2, à savoir :

Write Once Run Anywhere (Ecrire Une fois et Exécuter Partout) : en effet, la machine virtuelle Java permet la portabilité des applications. Par exemple, un développeur n’aura pas besoin d’écrire et de maintenir différentes versions d’une même application pour qu’elle puisse s’exécuter sur un Nokia Communicator (EPOC Operating System), sur un Compaq iPaq (Pocket PC Operating System) ou sur un PDA utilisant Linux comme système d’exploitation.

Sécurité : J2ME repose sur le modèle de sécurité Sandbox. Lorsqu’une application est exécutée elle ne peut accéder aux ressources système en dehors de la Sandbox ce qui limite les problèmes de virus. J2ME bénéficie également de solutions de sécurité pour les transactions électroniques comme SSL.

Une riche interface graphique : J2ME comporte des API riches et adaptées à chaque catégorie de terminaux mobiles.

1.2.1.1. Les machines virtuelles

La machine virtuelle Java (JVM) se trouve au centre de la technologie Java. Elle permet aux applications écrites dans le langage de programmation Java d’être portables sur différents environnements matériels et systèmes d’exploitation. La machine virtuelle se situe entre l’application et la plate-forme utilisée, convertissant le bytecode de l’application en code machine approprié au matériel et système d’exploitation utilisé. La machine virtuelle assume également des tâches relatives à la gestion de la mémoire du système. Deux machines virtuelles sont proposées par J2ME, la KVM associée à la configuration CLDC et la CVM associée à la configuration CDC [DSU04][DEL02].

KVM (Kilo Virtual Machine) est une implémentation runtime extrêmement légère de la machine virtuelle Java qui peut être utilisée dans les terminaux disposant de peu de mémoire, comme les téléphones cellulaires, les pagers bidirectionnels et les PDA. Cette machine virtuelle fonctionne avec des processeurs 16 et 32 bits et un total de mémoire d’environ 100 Ko.

CVM (Convergence Virtual Machine) est une machine virtuelle Java 2 conçue pour les terminaux ayant besoin de l’ensemble des

Travail de diplôme Roggo Jean-Christophe

- 10 -

fonctionnalités de la JVM mais avec des capacités plus réduites. CVM est conçue pour répondre aux besoins du marché émergent des terminaux embarqués de prochaine génération. Les terminaux utilisant CVM sont généralement des terminaux compacts.

D’autres machines virtuelles pour l’embarqué sont proposées par différents constructeurs comme la J9 (développée par IBM) associée à la configuration CDC, la Monty (développée par Sun), la MicrochaiVM (développée par HP) et la JBED (développée par la société suisse Esmertec) qui sont associées à la configuration CLDC. Ci-dessous vous trouverez un aperçu de l’offre en machines virtuelles embarquées [MVE02].

Editeur Machine virtuelle

Technologie Spécification OS Processeurs

Apogee Portage

optimisé des JVM de Sun

JIT + interpréteur, optimiseur

PJava, CDC, CLDC

LynxOS, VxWorks

PowerPC, x86, …

Esmertec JBED

Compilateur FastBCC

(bytecode to native)

CLDC/MIDP

PalmOS, PocketPC, Linux, Nucleus, JBED

Rtos

Arm 7/9 StrongArm, Xscale, PXA 210/250, PowerPC,

ColdFire, 68k

Chai VM AOT, JIT, adaptatif

Windows CE,

PocketPC, QNX SA1100, SH3/4,

x86 Hewlett Packard

Microchai VM AOT, JIT, adaptatif

Core, CLDC/MIDP Linux, PalmOS,

PocketPC

IBM Software Group

J9 AOT, JIT, adaptatif

Core, CLDC/MIDP,

CDC/FP

Linux, PalmOS, PocketPC, QNX,

Ose

x86, 68k, PowerPC,

StrongArm, SH4, Mips

Jeode adaptatif Personal Java

VxWorks, Nucleus,

Windows CE, Linux

Arm, Mips, SH3/4, PowerPC

Jeode EVM adaptatif CDC/FP Linux, VxWorks,

NT4 x86, Mips, PowerPC

Insignia

Mobile Foundation

adaptatif CLDC/MIDP Nucleus, iTron,

PocketPC Arm, Omap

Kada Systems Mobile ROI JIT +

interpréteur CLDC/MIDP

PalmOS, PocketPC, Wind,

Linux

Arm, TI, Mips, SH3/4

NewMonics Perc AOT, JIT, adaptatif

J2SE, J2ME/CDC

VxWorks, VxWorks AE, Nucleus, Ose,

Linux

PowerPC, x86, …

One Eighty Software

Origin - J propriétaire PJava, JavaCard Origin Microcontrôleurs 8

bits H8, 8051, 68xx et 16 bits

Sun Microsystems

Monty adaptatif CLDC/MIDP Arm, Jazelle

Tao Intent JTE JIT sans

interpréteur CLDC/MIDP

PocketPC, VxWorks,

SymbianOS Arm, Omap, Risc

Travail de diplôme Roggo Jean-Christophe

- 11 -

1.2.1.2. Les configurations

Comme nous l’avons cité précédemment, J2ME est une technologie basée sur une architecture modulaire. La configuration occupe une place importante dans cette architecture. Elle détermine une plate-forme minimale pour une catégorie de terminaux ayant des caractéristiques analogues en mémoire totale et en capacité de traitement. La configuration détermine une adjonction minimale ou « le plus petit dénominateur commun » à la technologie Java. Toutes les fonctionnalités inclues dans une configuration doivent être généralement applicables à une grande variété d’appareils. La technologie J2ME est constituée de deux configurations, CLDC (Connected Limited Device Configuration), pour les terminaux légers à connexion limitée, et CDC (Connected Device Configuration), pour les terminaux légers connectés.

CLDC JSR 30 est disponible comme implémentation de référence de CLDC. Cette configuration consiste en la machine virtuelle K (KVM) et un ensemble de bibliothèques de classes noyau appropriées à l’utilisation dans un profil de l’industrie, comme le profil spécifié par l’implémentation de référence MIDP. Les terminaux concernés sont dotés d’interfaces utilisateur simplifiées, de processeurs 16 ou 32 bits, d’une capacité mémoire disponible pour la plate-forme Java de 128 Ko à 512 Ko et de connexions réseau intermittentes à faible bande passante.

CDC JSR 36 est fondée sur la spécification de machine virtuelle classique qui définit un environnement runtime complet. Cette configuration est destinée aux terminaux disposant de ressources plus conséquentes, à savoir : une interface utilisateur très diversifiée, une capacité mémoire disponible pour la plate-forme Java dépassant en tout cas les 512 Ko, un processeur 32 bits et une connexion réseau permanente avec une large bande passante.

Notons qu’il existe une version révisée de CLDC 1.0 (JSR 30) : la version 1.1 de CLDC (JSR 139). Cette version révisée de CLDC inclut des nouvelles caractéristiques comme le support des nombres à virgule et l’emploi de références faibles. CLDC 1.1 est « rétro-compatible » avec la version CLDC 1.0. Une version révisée de CDC est en cours de développement et sera bientôt disponible: CDC 1.1 (JSR 218). [DEL02][DSU04][WJS04][JSU04]

1.2.1.3. Les profils

Le profil est également une pièce fondamentale de l’architecture modulaire de la technologie J2ME. C’est une couche située au dessus de la configuration qui correspond à une spécification d’API Java définie par l’industrie et utilisée par les fabricants et les développeurs pour des terminaux spécifiques. La machine virtuelle et les API de base spécifiées par une configuration ne suffisent pas pour construire une application complète. Le profil ajoute des API plus spécifiques

Travail de diplôme Roggo Jean-Christophe

- 12 -

pour la gestion du cycle de vie d’une application, l’interface graphique et le stockage permanent. Il existe deux familles de profils : ceux qui dépendent de la configuration CLDC et ceux qui dépendent de la configuration CDC. Ci-dessous vous trouverez une brève description des principaux profils existant dans J2ME.

MIDP est un profil qui nécessite l’implémentation de référence CLDC et qui fournit des classes pour l’écriture d’applications qui tournent sur des terminaux mobiles comme les téléphones cellulaires et les pagers bidirectionnels. Le profil MIDP fournit une plate-forme standard pour les petits terminaux mobiles aux ressources limitées. Ce profil est destiné aux terminaux répondant aux caractéristiques suivantes :

- 512 Ko de mémoire totale (ROM + RAM) disponible pour le runtime Java et ses bibliothèques ;

- puissance et batterie limitée ; - connectivité à certains type de réseaux sans fil à faible bande

passante ; - interfaces utilisateur à différents niveaux de sophistication.

Il existe à l’heure actuelle deux versions de MIDP : MIDP 1.0 (JSR 37) et MIDP 2.0 (JSR 118). MIDP 2.0 correspond à une version révisée de la spécification MIDP 1.0 qui inclut des nouvelles caractéristiques comme une interface graphique évoluée, des fonctionnalités pour les jeux et le multimédia ainsi que des possibilités étendues en matière de connectivité et de sécurité. Notons également que MIDP 2.0 est « rétro – compatible » avec MIDP 1.0.

PDAP JSR 75 est un profil associé à la configuration CLDC qui fournit des API d’interface utilisateur et de stockage de données pour les petits terminaux Handheld aux ressources limitées comme les PDA. Les terminaux visés ont les caractéristiques suivantes :

- pas moins de 512 Ko et pas plus de 16 Mo de mémoire totale (ROM + RAM) disponible pour le runtime Java et les bibliothèques ;

- puissance et batterie limitées ; - interface utilisateur de différents degrés de sophistication,

terminaux disposant d’un affichage d’une résolution supérieure à 20000 pixels, d’un dispositif de pointage et d’une entrée pour caractères.

Foundation Profile JSR 46 est un profil associé à la configuration CDC qui est destiné aux terminaux ayant besoin d’un support pour une plate-forme Java avec un réseau riche mais qui ne nécessitent pas d’interface utilisateur. Il fournit en outre un profil de base pour d’autres profils qui auraient besoin de construire leurs propres fonctionnalités en ajoutant, par exemple, une GUI (Graphical User Interface). Les terminaux visés ont les caractéristiques suivantes :

- 1024 Ko de ROM (sans compter les besoins mémoire des applications);

Travail de diplôme Roggo Jean-Christophe

- 13 -

- 512 Ko de RAM (sans compter les besoins mémoire des applications);

- connectivité à certains types de réseaux ; - aucune interface graphique (à moins que les fonctionnalités

d’interface graphique soient fournies par un profil additionnel).

Personal Profile JSR 62 est un profil associé à la configuration CDC qui est destiné aux terminaux nécessitant un haut niveau de connectivité Internet et une fidélité Web. Ce profil est conçu pour pour être compatible avec la spécification de l’environnement d’application PersonalJava. Les caractéristiques des terminaux visés sont les suivantes :

- un minimum de 2.5 Mo de ROM (sans compter les besoins mémoire des applications);

- un minimum de 1 Mo de RAM (sans compter les besoins mémoire des applications);

- connectivité robuste à certains types de réseaux ; - interface graphique avec un haut degré de fidélité Web et la

possibilité d’exécuter des applets ; - support de l’implémentation complète de J2ME Foundation Profile et

de J2ME CDC. [DEL02][DSU04][WJS04][JSU04]

1.2.1.4. Les packages optionnels

Le package optionnel est également un élément clé de l’architecture modulaire de la technologie J2ME. Un package optionnel fournit des fonctionnalités qui ne devraient pas être associées à une configuration ou à un profil particulier. Bluetooth API JSR 82 est un exemple de package optionnel qui fournit une API standard pour les connexions réseau sans fil Bluetooth. Ce package optionnel pourrait être implémenté avec n’importe quelle combinaison de configurations et de profils. Ci-dessous vous trouverez une description des principaux packages optionnels existant dans J2ME.

BTAPI JSR 82 (Bluetooth API) fournit une API standard pour l’intégration des terminaux mobiles dans un environnement Bluetooth. Cette spécification inclut le support des protocoles Bluetooth suivants : RFCOMM, OBEX et Service Discovery Protocol. D’autres protocoles seront ajoutés dans des versions futures de ce package optionnel. Les terminaux visés par cette spécification ont les caractéristiques suivantes :

- un minimum de 512 Ko de mémoire totale (ROM + RAM) - connexion réseau Bluetooth

Travail de diplôme Roggo Jean-Christophe

- 14 -

WMA JSR 120 (Wireless Messaging API) fournit une API standard pour accéder aux fonctionnalités de communication d’un terminal mobile. Les technologies concernées sont les suivantes :

- SMS (Short Message Service) - USSD (Unstructured Supplementary Service Data) - CBS (Cell Broadcast Service)

Notons qu’il existe une spécification plus récente, WMA 2.0 JSR 205, qui définit une interface pour l’envoi et la réception de MMS.

PIM JSR 75 (Personal Information Management) est un package optionnel offrant la possibilité d’accéder aux données natives résidant dans les terminaux mobiles comme les PDA ou les téléphones mobiles. Ce package permet par exemple d’accéder aux données contenues dans l’agenda ou le répertoire d’adresses d’un PDA.

MMAPI JSR 135 (Mobile Media API) définit une interface pour les fonctionnalités multimédia des terminaux mobiles compatibles J2ME.

Ci-dessous vous trouverez une illustration clarifiant l’architecture décrite précédemment suivie d’un tableau regroupant l’ensemble des JSR (configurations, profils et packages optionnels) concernant J2ME [DSU04]:

Travail de diplôme Roggo Jean-Christophe

- 15 -

Configurations

JSR 30 CLDC 1.0 Connected, Limited Device Configuration

JSR 139 CLDC 1.1 Connected, Limited Device Configuration 1.1

JSR 36 CDC Connected Device Configuration

JSR 218 CDC 1.1 Connected Device Configuration 1.1

Profils

JSR 37 MIDP 1.0 Mobile Information Device Profile

JSR 118 MIDP 2.0 Mobile Information Device Profile 2.0

JSR 75 PDAP PDA Profile

JSR 46 FP Foundation Profile

JSR 219 FP 1.1 Foundation Profile 1.1

JSR 129 PBP Personal Basis Profile

JSR 217 PBP 1.1 Personal Basis Profile 1.1

JSR 62 PP Personal Profile

JSR 215 PP 1.1 Personal Profile 1.1

JSR 195 IMP Information Module Profile

JSR 228 IMP-NG Information Module Profile - Next Generation

Packages optionnels

JSR 75 PIM PDA Optional Packages for the J2ME Platform

JSR 82 BTAPI Java APIs for Bluetooth

JSR 120 WMA Wireless Messaging API

JSR 205 WMA 2.0 Wireless Messaging API 2.0

JSR 135 MMAPI Mobile Media API

JSR 164 JAIN SIMPLE Presence

JSR 165 JAIN SIMPLE Instant Messaging

JSR 172 J2ME Web Services

JSR 177 SATSA Security and Trust Services API for J2ME

JSR 179 Location API for J2ME

JSR 180 SIP SIP API for J2ME

JSR 184 3D Mobile 3D Graphics API for J2ME

JSR 186 JAIN Presence

JSR 187 JAIN Instant Messaging

JSR 190 Event Tracking API for J2ME

JSR 209 Advanced Graphics and User Interface Optional Package for J2ME Platform

JSR 211 CHAPI Content Handling API

JSR 213 Micro WSCI Framework for J2ME

JSR 214 Micro BPSS for J2ME Devices

JSR 226 Scalable 2D Vector Graphics API

JSR 229 Payment API

JSR 230 Data Sync API

JSR 232 Mobile Operational Management

JSR 234 Advanced Multimedia Supplements

JSR 238 Mobile Internationalization API

JSR 239 Java Bindings for OpenGL ES

JSR 246 Device Management API

Travail de diplôme Roggo Jean-Christophe

- 16 -

1.2.1.5. La pile JSR 185 JTWI (Java Technology for the Wireless Industry)

Un terminal mobile compatible J2ME implémente une pile logicielle consistant généralement en une configuration, un profil et des packages optionnels. La première génération de téléphones mobiles compatibles J2ME implémente généralement la pile logicielle suivante :

Beaucoup de fabricants de téléphones mobiles proposent leurs propres API pour offrir des fonctionnalités étendues (généralement développées par l’intermédiaire de JCP). Il en résulte un phénomène de fragmentation. Un développeur MIDP désire savoir quelles API optionnelles sont disponibles pour des terminaux particuliers. Il est possible de découvrir la présence d’API au runtime, mais cette technique ajoute de la complexité au code. Il est également possible de distribuer plusieurs versions d’une application mais ceci dérogerait au principe fondamental des plate-formes Java, à savoir « write once and run everywhere ». Le phénomène de fragmentation peut donc engendrer des problèmes de portabilité. D’autres problèmes peuvent également limiter la portabilité d’une application. En effet, certains constructeurs fixent des limites pour la taille d’une application. Il peut arriver qu’une application MIDP 1.0 développée en respectant strictement les spécifications ne soit pas exécutable sur un terminal (MIDP 1.0 / CLDC 1.0). Le constructeur du terminal en question a pu fixer une limite pour la taille du fichier *.jar mais également une taille limite pour le heap (espace mémoire pour l’exécution de l’application). Le problème le plus délicat interférant sur la portabilité d’une application réside cependant dans l’utilisation des threads. La spécification MIDP 1.0 inclut la classe java.lang.Thread mais ne donne aucune indications sur le nombre de threads supportés par une implémentation. Si une application comporte un nombre importants de threads, elle risque de ne pas pouvoir s’exécuter correctement sur certains terminaux. Pour résoudre ces problèmes, une spécification particulière issue des travaux de la JSR 185 et nommée Java Technology for the Wireless Industry (JTWI) a été développée. Cette spécification impose aux périphériques qui la respectent de mettre en œuvre CLDC 1.0 ou 1.1, MIDP 2.0 et WMA. Le support de MMAPI est optionnel. La pile JSR 185 offre donc une vision claire au développeur des API disponibles pour un terminal mobile compatible JTWI.

Travail de diplôme Roggo Jean-Christophe

- 17 -

La spécification JSR 185 fournit tous les détails nécessaires pour garantir qu’une application sera exécutable sur tous les terminaux implémentant cette pile logicielle. Vous trouverez plus de détails sur la pile JSR 185 en consultant l’adresse suivante : http://developers.sun.com/techtopics/mobility/midp/articles/jtwi/ [DSU04][WJS04][JSU04]

1.2.1.6. Les autres API Java pour terminaux embarqués

Ces autres API Java ne font pas directement partie de J2ME mais il est tout de même intéressant de les citer. Certaines sont destinées au contrôle du téléphone, d’autres concernent la télévision numérique ou encore les cartes de crédit.

Java Phone API est une extension verticale de la plate-forme PersonalJava. Cette API fournit un accès aux fonctionnalités spécifiques des terminaux de téléphonie client. Elle permet notamment de contrôler le téléphone, d’envoyer des messages à base de datagrammes, d’obtenir des informations du carnet d’adresse et du calendrier.

Java TV API est une extension verticale de la plate-forme PersonalJava destinée à la création d’applications interactives pour la télévision numérique. Cette API permet la mise en œuvre de transactions de commerce électronique, de publicité interactive ou encore d’applications de banque à domicile.

Java Card est destinée au développement pour cartes intelligentes. Une carte intelligente est une carte de crédit dotée d’un circuit intégré (CI). Le CI contient un microprocesseur et de la mémoire permettant à la carte de stocker et traiter des informations. Java Card donne au développeur la possibilité de standardiser une plate-forme de carte commune. Cela signifie, par exemple, qu’un opérateur de téléphonie sans fil GSM (Global System for Mobile communications) peut facilement développer de nouveaux services susceptibles d’être téléchargés de manière sélective sur la carte intelligente résidant dans le téléphone.

Connexion Jini est une technologie permettant aux services de fonctionner dynamiquement et simplement avec d’autres services. Dans une communauté Jini, le services disposent d’un code de découverte et de recherche dont ils ont besoin pour fournir immédiatement les services aux autres membres de la communauté. Quand un nouveau service est mis à disposition sur le réseau, il n’est pas nécessaire d’éditer des fichiers de configuration, d’arrêter et de redémarrer des serveurs ou de configurer des passerelles. De plus, les communautés Jini supportent les infrastructures redondantes ce qui assure une disponibilité des services même en cas de pannes de serveurs ou de problèmes liés au réseau.

Travail de diplôme Roggo Jean-Christophe

- 18 -

JES (Java Embedded Server) est destiné aux périphériques de terminaison à large bande comme un modem DSL par exemple. Cette technologie permet de transformer le périphérique en passerelle résidentielle. Une passerelle résidentielle est un boîtier situé chez l’utilisateur lui permettant de se connecter à Internet et d’accéder à différents services. Les technologies JES et Connexion Jini sont liées. En effet, Connexion Jini supporte des communautés de services spontanément crées et JES est un framework permettant de générer les services délivrés à Jini.

[DEL02][WJS04][JSU04]

Travail de diplôme Roggo Jean-Christophe

- 19 -

Dans cette deuxième partie, vous trouverez une étude détaillée de la configuration CLDC.

2. La configuration CLDC

Le rôle de CLDC (Connected Limited Device Configuration) est de définir une plate-forme Java standard adaptées aux terminaux légers dotés de peu de ressources. CLDC répond à la nécessité de faire tourner des applications sur une grande variété de petits terminaux, allant des terminaux de communication sans fil, comme les téléphones cellulaires et les pagers bidirectionnels, jusqu’aux organiseurs personnels, aux terminaux de points de vente et aux équipements domestiques. CLDC est le plus petit commun dénominateur de la technologie Java applicable à une grande variété de terminaux mobiles. Il garantit la portabilité et l’interopérabilité du code au niveau des profils entre les différents types de terminaux mobiles compatibles CLDC. La configuration CLDC ne définit que les bases communes à l’ensemble des terminaux : entrées-sorties, réseau, sécurité, internationalisation. En ce qui concerne les fonctionnalités de plus haut niveau, c’est au profil spécifique du terminal de les prendre en charge : gestion du cycle de vie de l’application, interface utilisateur, gestion des évènements.

2.1. Les limitations de CLDC

La configuration CLDC est sujette à un certain nombre de limitations dont il faut tenir compte lors de la conception et du développement d’une application.

2.1.1. Support de la virgule flottante

CLDC ne supporte pas les nombres à virgule flottante float ou double. Lors du développement d’une application, il est donc impossible d’utiliser les types de données float et double.

Cette limitation n’est cependant pas catastrophique puisqu’il existe un package, MathFP, permettant de simuler les calculs en virgule flottante. Ce package est disponible à l’adresse suivante : http://home.rochester.rr.com/ohommes/MathFP [DEL02][WJS04][JSU04]

2.1.2. Internationalisation des applications

CLDC ne supporte que de manière limitée l’internationalisation, qui consiste à traduire les caractères UNICODE depuis et vers une séquence d’octets, d’une part, et vers la localisation, d’autre part.

Travail de diplôme Roggo Jean-Christophe

- 20 -

La conversion des caractères UNICODE est correctement assurée par l’utilisation des classes java.io.InputStreamReader et java.io.OutputStreamWriter. Cependant, les fonctionnalités de localisation ne sont pas spécifiées par CLDC. Pour être distribuée dans le monde entier, une application doit être internationalisée et localisée. Une application est dite internationalisée si elle gère plusieurs encodages de caractères. Une application est dite localisée si elle met en forme et interprète les dates, heures, zones horaires et monnaies selon les règles locales de l’utilisateur, ou, pour être plus précis, selon les règles de sa langue et de son pays. Dans J2SE, la réalisation d’applications internationalisée et localisée est facilitée grâce aux classes java.util.Calendar, java.util.Locale, java.text.Format et java.io.Reader.

Dans J2ME CLDC, les choses se compliquent car ces classes ne sont pas toutes présentes. CLDC comprend les classes de J2SE suivantes :

java.io.DataInputStream

java.io.DataOutputStream

java.io.InputStreamReader

java.io.OutputStreamWriter

java.io.Reader

java.io.Writer

java.util.Calendar

java.util.Date

java.util.Timezone

Les classes InputStreamReader et OutputStreamWriter assurent la conversion entre un flux d’octets et un flux de caractères UNICODE. Cette conversion est effectuée en fonction du système d’encodage de caractères utilisé sur le terminal.

Les classes Calendar, Date et TimeZone sont des sous-ensembles des classes J2SE de même nom. Elles permettent d’intégrer le support de la zone horaire locale de l’utilisateur. CLDC ne fournit rien de plus pour la localisation. C’est le rôle des profils d’ajouter éventuellement des nouvelles fonctionnalités. Par exemple, le profil MIDP prévoit l’implémentation d’une propriété système microedition.locale, qui retourne la locale du terminal au format langue-pays.

Il est important de réaliser que la principale contrainte lorsque l’on développe une application pour terminal mobile est l’espace mémoire (espace de stockage et espace d’exécution). La première mesure à prendre consiste donc à ne pas fournir qu’un seul fichier *.jar (JavaArchive) complet, qui prendrait en charge toutes les situations, mais plutôt à créer un fichier *.jar pour chaque cas. L’utilisateur téléchargera et installera la version de l’application pour son propre cas. Si ce téléchargement est réalisé depuis un serveur Web via un servlet, par exemple, ce dernier pourra même utiliser les en-têtes HTTP pour identifier la locale utilisée et retourner le fichier *.jar approprié. [DEL02][JSU04][API]

Travail de diplôme Roggo Jean-Christophe

- 21 -

2.1.3. Support des propriétés d’environnement

La classe java.util.Properties existant au sein de J2SE n’est pas implémentée dans la configuration CLDC. Toutefois, un jeu limité de propriétés commençant par le mot-clé microedition peut être accédé en appelant la méthode suivante : System.getProperty(String key); Le tableau ci-dessous dresse la liste de ces propriétés. Clé Description Valeur microedition.platform Plate-frome ou terminal hôte Par défaut : null microedition.encoding Encodage de caractères par défaut Par défaut : ISO8859_1 microedition.configurations Configuration et version J2ME Par défaut : CLDC-1.0 microedition.profiles Nom des profils supportés Par défaut : null

[DEL02][JSU04][API]

2.1.4. Limitations diverses

La configuration CLDC est confrontées à plusieurs autres limitations notamment concernant RMI (Remote Method Invocation), JNI (Java Native Interface) et les threads.

Pas de finalisation : CLDC ne propose pas de méthode de finalisation des instances de classe Object.finalize(). Il n’est donc pas possible de nettoyer un objet de la mémoire avant que le garbage collector le fasse (le garbage collector nettoie l’instance de la mémoire au moment où il constate que celle-ci n’est plus référencée).

Limitations dans la gestion des erreurs : la palette de classes d’erreur disponibles pour CLDC est limitée. La première raison à cela est que la gestion de certaines erreurs est spécifique au terminal cible. La deuxième raison est que le traitement des erreurs consomme beaucoup de ressources et qu’il fallait l’adapter à des terminaux disposant de peu de mémoire.

Pas de JNI : JNI n’est pas implémenté dans CLDC, d’abord pour des raisons de sécurité, ensuite parce que l’implémentation de JNI est trop coûteuse en mémoire.

Pas de chargeur de classe défini par l’utilisateur : pour des raisons de sécurité le chargeur de classe intégré ne peut être surchargé par l’utilisateur.

Ni réflexion, ni RMI, ni sérialisation d’objet : la réflexion n’est pas supportée, ce qui signifie que l’application ne peut pas inspecter le contenu des classes, des objets ou des méthodes. Par conséquent, toutes les fonctionnalités découlant de la réflexion comme RMI ou la sérialisation d’objets ne sont pas supportées dans CLDC.

Travail de diplôme Roggo Jean-Christophe

- 22 -

Pas de groupe de threads ou de threads démons : le multithreading est implémenté dans CLDC, mais les groupes de threads ou les threads démons ne le sont pas. Les threads démons sont des threads qui tournent en tâche de fond et proposent des services aux autres threads.

Pas de références faibles : les références faibles ne sont pas autorisées dans CLDC. Une référence faible est un type de référence vers un objet qui permet de déterminer si un objet est finalisé. Elle permet de conserver une référence vers l’objet sans l’empêcher d’être pris en compte par le garbage collector.

[DEL02][JSU04]

2.2. La sécurité dans CLDC

Les contraintes de taille mémoire ne permettent pas l’utilisation du modèle de sécurité de J2SE dans J2ME. La prise en charge de la sécurité dans J2ME se traduit par un mécanisme de prévérification des fichiers de classe puis par le modèle de sécurité Sandbox.

2.2.1. Prévérification des fichiers de classe

Lorsqu’un fichier de classe est chargé, sa validité est vérifiée. Dans J2SE, cette vérification est effectuée au moment de l’exécution (runtime) par la machine virtuelle. Il est évident que les contraintes de taille mémoire auxquelles sont confrontés les terminaux mobiles ne permettent pas d’implanter le même mécanisme que dans J2SE. CLCD définit donc un autre mécanisme de vérification des fichiers de classes. Chaque méthode dans un fichier de classe Java téléchargé contient un nouvel attribut. Cet attribut est ajouté au fichier de classe standard par un utilitaire nommé prévérificateur (Preverifier). Le rôle de cet outil est d’analyser chaque méthode se trouvant dans le fichier de classe. Cette prévérification est généralement effectuée sur un ordinateur de bureau avant que le fichier de classe soit téléchargé sur le terminal.

Travail de diplôme Roggo Jean-Christophe

- 23 -

Comme l’illustre le schéma précédent, dans J2ME, une partie du travail de vérification des fichiers de classes est effectuée sur la station de développement de sorte à alléger la tâche du terminal cible. Cette solution permet aux machines virtuelles Java compatibles CLDC de vérifier les fichiers de classes beaucoup plus rapidement. Le mécanisme consomme un minimum de mémoire tout en garantissant le même niveau de sécurité qu’avec la solution standard déployée dans J2SE. [DEL02][JSU04][DSU04]

2.2.2. Le modèle de sécurité Sandbox

Le principe du modèle de sécurité Sandbox Original est de considérer que le code local est autorisé à avoir un accès total aux ressources vitales du système tandis qu’un code téléchargé est suspect et ne peut accéder aux ressources fournies à l’intérieur du Sandbox. Le Sandbox est donc une zone permettant d’exécuter en toute sécurité un code qui aurait pu être dangereux pour le système. Notons aussi que l’ensemble des fonctions natives accessibles à la machine virtuelle est délimité. Le développeur ne peut pas télécharger de nouvelles bibliothèques contenant des fonctionnalités natives, ni accéder à des fonctions natives ne faisant pas partie des bibliothèques Java fournies par CLDC ou les profils. [DEL02][JSU04]

2.3. Les classes de CLDC

Cette section présente les classes disponibles au sein de la configuration CLDC. CLDC comporte des classes héritées de J2SE et des classes spécifiques.

2.3.1. Les classes héritées de J2SE

Les classes héritées de J2SE existant au sein de CLDC proviennent des packages java.lang, java.io et java.util. Le package java.lang contient les classes sytème, les classes de type et les classes d’exception. Le package java.io propose des classes de lecture-écriture des flux de base. Le package java.util, quant à lui, fournit des classes utilitaires de base. Les classes reprises de J2SE dans CLDC sont pour la plupart allégées (méthodes simplifiées ou supprimées) de telle manière à ce qu’elles soient adaptées aux contraintes de taille mémoire. Un certains nombre de packages sont inexistants dans CLDC, notamment : java.lang.awt, java.lang.rmi, java.lang.security, et java.lang.sql.

Les classes contenues dans ces packages ne sont pas implémentées dans la configuration CLDC en raison des limitations de la KVM et des contraintes de taille mémoire auxquelles sont confrontés les terminaux mobiles compatibles CLDC.

Travail de diplôme Roggo Jean-Christophe

- 24 -

Le tableau ci-dessous recense les classes héritées de J2SE par CLDC. Type Package Classes Classes système java.lang Object, Class, Runtime, System, Thread,

Runnable, String, StringBuffer, Throwable Classes de type de données

java.lang Boolean, Byte, Short, Integer, Long, Character

Classes d’exception java.lang

Exception, ClassNotFoundException,IllegalAccessException, InstantiationException, InterruptedException, RuntimeException, ArithmeticException, ArrayStoreException, ClassCastException, IllegalArgumentException, IllegalThreadStateException, NumberFormatException, IllegalMonitorStateException, IndexOutOfBoundsException, ArrayIndexOutOfBoundsException, StringIndexOutOfBoundsException, NegativeArraySizeException, NullPointerException, SecurityException

Classes d’erreur java.lang Error, VirtualMachineError, OutOfMemoryError Classes de collection java.util Vector, Stack, Hashtable, Enumeration Classes de calendrier et d’horloge

java.util Calendar, Date, Timezone

Classes d’exception java.util EmptyStackException, NoSuchElementException

Classes d’exception java.io

EOFException, IOException, InterruptedException, UnsupportedEncodingException, UTFDataFormatException

Classes d’entrées-sorties java.io

InputStream, OutputStream, ByteArrayInputStream, ByteArrayOutputStream, DataInput, DataOutput, DataInputStream, DataOutputStream, Reader, Writer, InputStreamReader, OutputStreamWriter, PrintStream

Classes utilitaires java.util, java.lang Java.util.Random, java.lang.Math

[DEL02][API]

2.3.2. Les classes spécifiques de CLDC

En ce qui concerne les entrées-sorties et la connectivité réseau, la configuration CLDC n’hérite pas de la totalité des classes contenues dans le package java.io de J2SE. De nouvelles classes ont été définies et regroupées sous le nom de GCF (Generic Connection Framework) dans le package javax.microedition.io.

Ces classes spécifiques à la configuration CLDC sont les suivantes :

Connection

HttpConnection

ConnectionNotFoundException

Connector

ContentConnection

Datagram

DatagramConnection

InputConnection

OutputConnection

Travail de diplôme Roggo Jean-Christophe

- 25 -

StreamConnection

StreamConnectionNotifier

Comme son nom l’indique, CLDC (Connected Limited Device Configuration) est conçue pour les terminaux pouvant se connecter au monde extérieur, que ce soit par liaison série, infrarouge ou sans fil. C’est l’objet du GCF (Generic Connection Framework), qui regroupe un ensemble de classes et d’interfaces modélisant des types différents de connexions, allant de la simple connexion unidirectionnelle à une connexion datagramme. Le GCF repose sur la notion d’abstraction de la même manière que JDBC pour les accès aux bases de données. Toutes les connexions sont crées avec une même méthode statique dans une classe appelée javax.microedition.Connector. L’instruction permettant d’ouvrir une connexion aura la forme suivante : Connector.open(“<protocole>:<adresse>;<paramètres>”); CLDC ne définit pas d’implémentation de protocole. Ce sont les profils qui doivent implémenter certains des protocoles proposés par les spécifications de CLDC. Les différents protocoles que CLDC propose sont listés dans le tableau ci-dessous. Protocole Valeur Exemple HTTP http Connector.open(“http://www.ruchat.ch”) ; Socket Socket Connector.open(“socket://222.223.223.222:1111”); Port de communication série

comm Connector.open(“comm.:0; baudrate=9600”);

Datagramme datagram Connector.open(“datagram://222.223.223.222”); Fichier file Connector.open(“file:config.dat”); Système de fichiers réseau

nfs Connector.open(“nfs:/netinnovations.fr/config.dat”);

Le GCF définit huit types de connexions toutes représentées sous la forme d’interfaces de connexion définies dans le package javax.microedition.io.

Le tableau ci-dessous recense ces connexions. Interface Description ContentConnection Permet une communication HTTP de base. Ne supporte

que l’encodage de caractères, le type MIME et la taille.

StreamConnectionNotifier Permet une communication avec un client via une connexion par socket côté serveur.

InputConnexion Gère une connexion en entrée. OutputConnection Gère une connexion en sortie.

DatagramConnection Permet de communiquer avec une connexion datagramme (UDP p.ex)

Connection Objet de connexion de base. StreamConnection Permet une communication basée sur les sockets. HttpConnection Permet de communiquer avec le protocole HTTP 1.1.

Travail de diplôme Roggo Jean-Christophe

- 26 -

Ces différentes interfaces de connexions sont organisées selon la hiérarchie présentée dans le schéma ci-dessous.

«interface»Connection

«interface»StreamConnectionNotifier

«interface»InputConnection

«interface»OutputConnection

«interface»DatagramConnection

«interface»StreamConnection

«interface»ContentConnection

«interface»HttpConnection

Vous trouverez un exemple de mise en œuvre du composant HttpConnection dans l’annexe n°3. Pour plus de détails concernant la configuration CLDC consultez la référence suivante : http://jcp.org/aboutJava/communityprocess/final/jsr030/index.html [DEL02][API]

Travail de diplôme Roggo Jean-Christophe

- 27 -

Dans cette troisième partie, vous trouverez les éléments théoriques nécessaires pour entreprendre un développement MIDP (Mobile Information Device Profile).

3. Le profil MIDP

Un MIDlet est une application développée pour MIDP. C’est en quelque sorte un applet destiné à un terminal mobile MIDP et non pas à un navigateur Web. Le cycle de vie du développement d’une application pour MIDP est constitué des étapes suivantes :

Ecriture de l’application avec les API de MIDP.

Compilation et prévérification de l’application.

Test de l’application avec un émulateur.

Packaging de l’application.

Test de l’application packagée sur le terminal mobile.

Nous reviendrons plus en détails sur ces différentes étapes dans la partie pratique de ce dossier.

3.1. Le MIDlet

3.1.1. Cycle de vie d’un MIDlet

Toutes les applications développées pour le profil MIDP doivent dériver de la classe abstraite MIDlet contenue dans le package javax.microedition.midlet. La classe MIDlet gère le cycle de vie de l’application. Un MIDlet peut se retrouver dans quatre états différents :

chargé (loaded)

actif (active)

suspendu (paused)

détruit (destroyed)

Lorsqu’un MIDlet est chargé sur un terminal et que le constructeur est appelé son état est chargé (loaded). C’est état précède l’état actif (active) découlant de l’appel de la méthode startApp() par le gestionnaire d’application. Le gestionnaire d’application est un logiciel dépendant du terminal mobile. Il est implémenté par le fabricant du terminal. Ce gestionnaire gère l’installation, l’exécution et le retrait des MIDlets sur le terminal. Il fournit généralement un mécanisme de gestion des erreurs. Après l’appel de la méthode startApp() le MIDlet se retrouve dans l’état actif jusqu’à ce que le gestionnaire appelle la méthode pauseApp() ou destroyApp() : pauseApp() suspend le MIDlet tandis que destroyApp(boolean unconditional) termine l’exécution du MIDlet.

Travail de diplôme Roggo Jean-Christophe

- 28 -

Les trois méthodes permettant de gérer le cycle de vie d’un MIDlet sont des méthodes abstraites et doivent obligatoirement être redéfinies. Le squelette d’une application pour le profil MIDP sera donc le suivant : import javax.microedition.midlet.* ; public class Test extends MIDlet { public Test() { } public void startApp() { } public void pauseApp() { } public void destroyApp(boolean unconditional) { } }

La figure ci-dessous donne un aperçu du cycle de vie d’un MIDlet.

La méthode pauseApp() permet de libérer les ressources qui ne sont pas nécessaires lorsque l’application est suspendue. Un MIDlet exécuté sur un téléphone mobile sera par exemple suspendu au moment ou l’utilisateur reçoit un appel téléphonique. Le MIDlet devra alors libérer les ressources jusqu’à la reprise de son exécution.

La méthode destroyApp(boolean unconditional) prend un paramètre de type booléen en entrée. Si ce paramètre est false, le MIDlet peut refuser qu’on termine son exécution en lançant l’exception MIDletStateChangeException.

Travail de diplôme Roggo Jean-Christophe

- 29 -

La méthode resumeRequest() permet au MIDlet d’indiquer son intention de passer à l’état actif. Lorsqu’un MIDlet décide de se mettre dans l’état suspendu, il doit informer le gestionnaire d’application en appelant la méthode notifyPaused(). Le gestionnaire d’application doit également être informé de la fin de l’exécution d’un MIDlet en appelant la méthode notifyDestoyed().

[DEL02][JSU04]

3.1.2. L’accès aux attributs du fichier *.jar

Le moyen le plus simple pour distribuer une application MIDP est d’utiliser le format de fichier archive *.jar. Un certain nombre de fichiers sont regroupés dans un fichier archive *.jar. Ce sont les fichiers de classes, les fichiers de ressources (des images au format *.png par exemple) et le fichier décrivant le contenu du fichier *.jar lui-même. Ce dernier fichier se nomme manifest.mf. Le tableau ci-dessous dresse la liste des attributs pouvant être définis dans le fichier manifest.mf. Attributs Description MIDlet-Name Nom du package MIDlet MIDlet-Version Numéro de version du MIDlet MIDlet-Vendor Auteur du MIDlet MIDlet-Icon Icône associée au MIDlet (image au format *.png) MIDlet-Description Description du MIDlet

MIDlet-Info-URL URL pouvant fournir des informations supplémentaires sur le MIDlet et/ou le vendeur

MIDlet-<n> Contient trois informations : le nom du MIDlet, l’icône de ce MIDlet, le nom de la classe chargée par le gestionnaire d’applications

MIDlet-Jar-URL URL du fichier *.jar MIDlet-Jar-Size Taille du fichier *.jar (en octets)

MIDlet-Data-Size Nombre minimum d’octets nécessaires pour le stockage de données persistantes

MicroEdition-Profile Profil J2ME imposé par le MIDlet MicroEdition-Configuration Configuration J2ME imposée par le MIDlet

Seuls les attributs MIDlet-Name, MIDlet-Version, MIDlet-Vendor, MIDlet-<n>, MicroEdition-Profile et MicroEdition-Configuration sont obligatoires.

Un MIDlet peut accéder aux attributs contenus dans le fichier manifest.mf grâce à la méthode javax.microedition.midlet.MIDlet.getAppProperty(String key). Pour obtenir des informations sur l’auteur du MIDlet on utilisera la méthode de cette manière : String infoAuteur = getAppProperty(“MIDlet-Vendor”); [DEL02][API]

Travail de diplôme Roggo Jean-Christophe

- 30 -

3.2. L’interface utilisateur

Comme nous l’avons vu dans la deuxième partie de ce dossier, la configuration CLDC ne fournit pas les classes nécessaires au développement d’une interface utilisateur. C’est le rôle du profil de fournir ces classes. Cette section présente les API proposées par le profil MIDP pour le développement d’une interface utilisateur. L’interface utilisateur des terminaux mobiles est sujette à des contraintes différentes de celles d’un ordinateur de bureau (taille de l’affichage restreinte, pas de souris …). C’est pourquoi les API d’interface utilisateur fournies par MIDP ne s’appuient pas sur les API de J2SE comme AWT (Abstract Window Toolkit) ou Swing.

3.2.1. Les principes de l’interface utilisateur MIDP

L’interface utilisateur MIDP est constituée de deux API, l’une de haut niveau et l’autre de bas niveau. La première API a un haut niveau d’abstraction, qui assure un non moins haut niveau de portabilité. Cette API offre peu de contrôle sur l’apparence visuelle (forme, couleur, police de caractères) des composants. La seconde API a un faible niveau d’abstraction. Elle offre un contrôle précis du positionnement et de la gestion des éléments graphiques. Elle permet également d’accéder aux événements de saisie. Les MIDlets qui accèdent à l’API de bas niveau ne garantissent pas la portabilité car cette API fournit des fonctionnalités spécifiques aux terminaux, comme la taille de l’écran ou l’utilisation d’un système de pointage.

L’interface utilisateur repose sur la notion d’écran, ou Screen, un objet qui encapsule les composants graphiques du terminal. Un seul écran peut être visible à la fois et l’utilisateur navigue parmi les composants de cet écran. On distingue trois types d’écran :

Ecran comprenant des composants complexes, comme les composants List ou TextBox. Sa structure est prédéfinie, et l’application ne peut y ajouter d’autres composants.

Ecran comprenant un composant formulaire Form. L’application peut ajouter du texte, une image et des composants liés au formulaire.

Ecran utilisé avec l’API de bas niveau, comme les sous-classes de la classe Canvas.

La classe Display est le gestionnaire d’affichage utilisé par le MIDlet. Elle fournit entre autres les méthodes nécessaires pour connaître les capacités d’affichage du terminal. Pour rendre visible un écran, il suffit d’appeler la méthode setCurrent(Displayable nextDisplayable) de la classe Display.

Un certain nombre de règles sont à respecter lors du développement d’une interface graphique avec le profil MIDP :

Concevoir des interfaces utilisateur simples et faciles à utiliser.

Utiliser l’API de haut niveau pour garantir au maximum la portabilité.

Travail de diplôme Roggo Jean-Christophe

- 31 -

L’application ne doit pas dépendre d’une taille d’écran particulière, elle doit demander au terminal la taille de l’affichage et s’adapter à cette contrainte.

La saisie d’information pouvant être pénible, il faut privilégier les listes de choix dans lesquelles l’utilisateur est invité à faire une sélection.

Eviter l’utilisation de bibliothèques de classes tierces comme kAWT, qui est une version allégée de AWT adaptée à la KVM.

[DEL02][JSU04][API]

3.2.2. Les classes d’affichage

Les briques de base de l’interface utilisateur MIDP sont les calsses Displayable, Display, Screen et Canvas contenus dans le package javax.microedition.lcdui.

La figure ci-dessous présente la hiérarchie des classes de l’interface utilisateur MIDP.

[DEL02][API]

3.2.2.1. La classe Display

La classe Display correspond au gestionnaire d’affichage. Elle permet de lire les propriétés du terminal et de demander l’affichage des objets sur le terminal. Il ne peut y avoir qu’une seule instance de Display par MIDlet. Cette unique instance peut être obtenue à n’importe quel moment durant l’exécution du MIDlet en appelant la méthode suivante :

Travail de diplôme Roggo Jean-Christophe

- 32 -

static Display getDisplay(MIDlet m) A un gestionnaire d’affichage peut correspondre plusieurs objets affichables (Displayable). Pour obtenir l’objet Displayable courant, la méthode suivante doit être appelée : Displayable getCurrent() Le tableau ci-dessous regroupe l’ensemble des méthodes de la classe Display.

Méthode Description Displayable getCurrent() Retourne une référence à l’objet Displayable courant void setCurrent(Displayable nextDisplayable) void setCurrent(Alert alert, Displayable nextDisplayable)

Spécifie un nouvel objet Displayable, en précisant éventuellement une alerte qui sera affichée avant que l’objet nextDisplayable soit affiché.

boolean isColor() Indique si le terminal supporte les couleurs. int numColors() Retourne le nombre de couleurs supportées. static Display getDisplay(MIDlet m) Retourne l’objet Display, unique pour ce MIDlet.

void CallSerially(Runnable r) Appelle l’objet spécifié dès la fin du cycle repaint (lors de l’utilisation de l’interface utilisateur bas niveau).

[DEL02][API]

3.2.2.2. La classe Displayable

La classe abstraite Displayable modélise un objet qui peut être affiché à l’écran. Cette classe est la super classe commune des classes abstraites Screen (API haut niveau) et Canvas (API bas niveau).

Le tableau ci-dessous liste les méthodes de la classe Displayable.

Méthodes Description void addCommand(Command cmd) void removeCommand(Command cmd) Ajoute et retire une commande.

boolean isShown() Indique si l’objet Displayable est visible ou non. void setCommandListener(CommandListener l) Met en place un listener. Ticker getTicker() void setTicker(Ticker ticker) Permet d’associer un ticker à l’objet affichable.

[DEL02][API]

3.2.2.3. La classe Screen

La classe abstraite Screen dérive de la classe Displayable. Elle correspond à la brique principale de l’API d’interface utilisateur de haut niveau. Le contenu de l’affichage et l’interaction avec l’utilisateur sont définis par les sous-classes de Screen. Le contenu affiché est rafraîchi automatiquement (nul besoin d’appeler une méthode spécifique). Il est d’ailleurs recommandé qu’une application ne change le contenu affiché que lorsque celui-ci n’est pas visible (pendant qu’un autre objet Displayable est en cours d’affichage par exemple). Changer le

Travail de diplôme Roggo Jean-Christophe

- 33 -

contenu d’un objet Screen lorsqu’il est visible peut poser des problèmes de performances sur certains terminaux.

La classe Screen hérite naturellement de toutes les méthodes de sa super classe Displayable.

[DEL02][API]

3.2.2.4. La classe Canvas

La classe abstraite Canvas est la sous-classe de Displayable qui correspond à la brique principale de l’API d’interface utilisateur bas niveau. Lorsqu’on étend la classe Canvas, il faut impérativement implémenter la méthode abstraite paint(). Par défaut, les implémentations des méthodes de gestion des évènements sont vides. On ne surchargera donc que les méthodes utilisées. De manière générale, on utilise la classe Canvas pour accéder aux évènements de bas niveau et les gérer. Il est également possible de gérer les évènements de haut niveau en ajoutant des commandes au Canvas grâce aux méthodes addCommand(Command cmd) et setCommandListener(CommandListener l) héritées de la super-classe Displayable. Les tableaux ci-dessous dressent la liste des méthodes et des champs de la classe Canvas.

Méthodes Description protected Canvas() Constructeur de la classe Canvas

String getKeyName(int keyCode) int getGameAction(int keyCode) int getKeyCode(int gameAction)

Détecte la touche pressée. La première retourne le nom de la touche, la deuxième l’action de jeu associée à la touche actionnée et la troisième l’opération inverse, à savoir le code de la touche associée à l’action de jeu spécifiée.

protected void keyPressed(int keyCode) protected void keyReleased(int keyCode) protected void keyRepeated(int keyCode)

Gère les touches pressées, relâchées et actionnées de manière répétitive.

boolean hasRepeatEvents() Indique si l’événement keyRepeated est supporté.

boolean hasPointerEvents() Indique si un système de pointage est disponible sur le terminal.

boolean hasPointerMotionEvents() Indique si le terminal supporte les évènements de déplacement du pointeur.

protected void pointerDragged(int x, int y) protected void pointerPressed(int x, int y) protected void pointerReleased(int x, int y)

Gère les événements de déplacement, de pression et de relâchement du pointeur.

int getHeigth() int getWidth() Retourne la dimension de la zone Displayable.

boolean isDoubleBuffered() Indique si les graphiques sont gérés avec un double-tampon.

void repaint() void repaint(int x, int y, int width, int heigth)

Retrace le contenu du Canvas dans sa totalité ou partiellement.

Evidemment, la classe Canvas hérite de toutes les méthodes de sa super-classe Displayable.

Champ Description DOWN Touche pour descendre FIRE Touche pour faire feu GAME_A Touche A

Travail de diplôme Roggo Jean-Christophe

- 34 -

GAME_B Touche B GAME_C Touche C GAME_D Touche D KEY_NUM0 Touche numérique 0 KEY_NUM1 Touche numérique 1 KEY_NUM2 Touche numérique 2 KEY_NUM3 Touche numérique 3 KEY_NUM4 Touche numérique 4 KEY_NUM5 Touche numérique 5 KEY_NUM6 Touche numérique 6 KEY_NUM7 Touche numérique 7 KEY_NUM8 Touche numérique 8 KEY_NUM9 Touche numérique 9 KEY_POUND Touche dièse (#) KEY_STAR Touche étoile (*) LEFT Touche pour aller à gauche RIGHT Touche pour aller à droite UP Touche pour aller en haut

[DEL02][API] Ce dossier n’abordera pas plus en détail l’API d’interface utilisateur de bas niveau. La section suivante traite de l’interface utilisateur de haut niveau de manière détaillée. Notons que seules les classes et méthodes du profil MIDP 1.0 sont décrites dans la section suivante. Des classes et méthodes supplémentaires ont été ajoutées dans la version 2.0 de MIDP (cf documentation fournie avec l’outil J2ME Wireless Toolkit 2.1).

3.2.3. L’interface utilisateur de haut niveau

L’API de haut niveau permet d’utiliser des composants d’interface utilisateur, mais aucun accès direct à l’écran ni aux événements de saisies n’est possible. C’est l’implémentation MIDP qui décide de la manière de représenter les composants et du mécanisme de gestion des saisies de l’utilisateur. Notons qu’il est possible d’utiliser l’API de haut niveau et l’API de bas niveau dans un même MIDlet mais pas simultanément. Par exemple, les jeux qui utilisent l’API de bas niveau pour contrôler l’écran peuvent également utiliser l’API de haut niveau pour l’affichage des meilleurs scores. Les composants proposés par l’API de haut niveau MIDP sont regroupés au sein du package javax.microedition.lcdui.

Les deux tableaux ci-dessous recensent les classes et interfaces de l’API d’interface utilisateur de haut niveau contenues dans le package javax.microedition.lcdui.

Interface Description Choice Définit la sélection d’un élément d’un groupe de choix

prédéfini. CommandListener Permet de gérer les évènements de haut niveau.

ItemStateListener Permet de gérer les évènements de changement interne aux éléments interactifs (dans un composant Form)

Classe Description Alert Permet l’affichage d’un message d’alerte. AlertType Fournit une indication sur la nature de l’alerte.

Travail de diplôme Roggo Jean-Christophe

- 35 -

ChoiceGroup Implémente un groupe d’éléments Choice. Utilisé dans un Form.

Command Implémente une commande. Ne contient pas les actions déclenchées par l’activation de la commande.

DateField Implémente un champ de date et heure. Utilisé dans un Form.

Form Implémente un formulaire. C’est un conteneur pour un ensemble d’éléments disparates (image, texte …)

Gauge Implémente une jauge graphique. Image Implémente une image graphique. ImageItem Permet de spécifier la disposition d’une Image dans un

formulaire ou dans une alerte. Item Super-classe de tous les composants pouvant être

ajoutés à un Form ou à une Alert. List Implémente une liste de choix (menu). StringItem Implémente un élément associable à un composant

Form et contenant une chaîne de caractères non modifiable.

TextBox Implémente une zone de saisie. TextField Implémente une zone de saisie associable à un

composant Form. Ticker Implémente un composant permettant de faire défiler

du texte en continu sur l’écran.

[DEL02][API] Vous trouverez dans l’annexe n°1 un exemple récapitulatif complet dans lequel la plupart de ces classes sont utilisées.

3.2.3.1. L’interface Choice

L’interface Choice définit les caractéristiques d’une liste de choix. Les classes ChoiceGroup et List implémentent cette interface. Les méthodes et les champs définis dans l’interface Choice sont recensés dans les tableaux ci-dessous [DEL02][API]. Méthode Description int append(String stringPart, Image imagePart) Ajoute un élément et son image associée en fin de

liste. void insert(int elementNum, String stringPart, Image imagePart)

Insère un élément et son image associée juste avant l’élément spécifié.

void delete(int elementNum) Supprime l’élément spécifié de la liste. int getSelectedFlags(boolean[] selectedArray_return) void setSelectedFlags(boolean[] selectedArray)

Lit et modifie le status de selection des elements de la liste.

int size() Retourne le nombre d’éléments de la liste. String getString(int elementNum) Image getImage(int elementNum)

Lit le texte et l’image associée de chaque élément de la liste.

void set(int elementNum, String stringPart, Image imagePart) Modifie un élément de la liste.

void setSelectedIndex(int elementNum, boolean selected) Sélectionne ou désélectionne un élément de la liste.

int getSelectedIndex() Retourne le numéro de l’élément sélectionné. boolean isSelected(int elementNum) Indique si l’élément est sélectionné ou on.

Champ Description EXCLUSIVE L’utilisateur ne peut sélectionner qu’un seul élément à

la fois.

IMPLICIT L’élément qui possède le focus est sélectionné quand une commande est activée.

MULTIPLE L’utilisateur peut sélectionner plusieurs éléments.

Travail de diplôme Roggo Jean-Christophe

- 36 -

3.2.3.2. La classe List

La classe List implémente l’interface Choice et étend la classe abstraite Screen. Elle permet de créer et de manipuler une liste de choix. On utilisera volontiers cette classe pour implémenter un menu. La classe List implémente l’ensemble des méthodes de l’interface Choice (cf tableaux de la sectiion 3.2.3.1) et propose en outre les deux constructeurs et le champ décrits dans les tableaux ci-dessous [DEL02][API]. Méthode Description

List(String title, int listType) List(String title, int listType, String[] stringElements, Image[] imageElements)

Constructeurs de la classe List. Le premier crée une liste en spécifiant son titre et son type. Le second crée une liste en spécifiant en plus les éléments textuels et graphique la constituant.

Champ Description

SELECT_COMMAND C’est une commande spéciale que commandAction peut utiliser pour savoir que l’utilisateur a sélectionné un élément dans une liste IMPLICIT.

Les champs EXCLUSIVE, IMPLICIT et MULTIPLE sont hérités de l’interface javax.microedition.lcdui.Choice. Ces champs spécifie le type de liste. Si le type de liste est EXCLUSIVE, l’utilisateur ne peut sélectionner qu’un seul élément à la fois. Si le type de liste est IMPLICIT, l’élément qui possède le focus est sélectionné lorsqu’une commande est activée. Si le type de liste est MULTIPLE, l’utilisateur peut sélectionner plusieurs éléments à la fois.

Ci-dessous vous trouverez une illustration du composant List implémentant le menu principal du MIDlet testGUI (cf annexe n° 1).

Travail de diplôme Roggo Jean-Christophe

- 37 -

3.2.3.3. La classe Item

La classe abstraite Item est la super classe de tous les composants pouvant être associés à un formulaire (cf 3.2.3.4). Elle comprend les méthodes présentées dans le tableau ci-dessous [DEL02][API]. Méthode Description String getLabel() void setLabel(String label)

Permet de lire et de modifier l’étiquette associée à l’élément.

3.2.3.4. La classe Form

La classe Form dérive de la classe abstraite Screen. Elle permet d’utiliser un formulaire auxquel peut être associé un ensemble d’éléments disparates (image, texte, champ de texte, liste de choix …) dérivant tous de la classe abstraite Item (cf 3.2.3.3). Les méthodes de cette classe sont présentées dans le tableau ci-dessous [DEL02][API]. Méthode Description Form(String title) Form(String title, Item[] items)

Constructeurs permettant de créer un formulaire en spécifiant son titre uniquement ou en spécifiant son titre et ses éléments associés.

int append(Item item) int append(Image img) int append(String str)

Permet d’ajouter un élément de type Item, une image ou du texte.

void insert(int itemNum, Item item) Permet d’insérer un élément de type Item dans le formulaire à la place spécifiée.

void delete(int itemNum) Permet de supprimer du formulaire l’élément spécifié. Item get(int itemNum) void set(int itemNum, Item item)

Permet de lire et de modifier les éléments du formulaire.

int size() Retourne le nombre d’éléments contenus dans le formulaire.

void setItemStateListener(ItemStateListener iListener)

Permet de mettre en place un listener pour le formulaire.

La classe Form hérite évidemment de toutes les méthodes implémentées dans la classe abstraite Screen.

Ci-dessous vous trouverez une illustration du composant Form mis en œuvre dans l’application testGUI (cf annexe n° 1).

Travail de diplôme Roggo Jean-Christophe

- 38 -

3.2.3.5. La classe ChoiceGroup

La classe ChoiceGroup implémente l’interface Choice et hérite de la classe abstraite Item (cf 3.2.3.3). Le composant ChoiceGroup doit être associé à un formulaire (cf 3.2.3.4). Cette classe permet d’utiliser une liste de choix au sein d’un formulaire. Elle implémente l’ensemble des méthodes de l’interface Choice (cf 3.2.3.1) et propose en outre les deux constructeurs présentés dans le tableau ci-dessous [DEL02][API]. Méthode Description ChoiceGroup(String label, int choiceType) Permet de créer une liste de choix en précisant

l’intitulé et le type (EXCLUSIVE, IMPLICIT, MULTIPLE). ChoiceGroup(String label, int choiceType, String[] stringElements, Image[] imageElements)

Permet de créer une liste de choix en fournissant les éléments de cette liste en paramètre sous forme de tableaux.

La classe ChoiceGroup hérite naturellement des méthodes de la classe Item. Ci-dessous vous trouverez une illustration du composant ChoiceGroup mis en œuvre dans l’application testGUI (cf annexe n° 1).

3.2.3.6. La classe TextField

La classe TextField dérive de la classe Item (cf 3.2.3.3). Cela signifie donc que ce composant doit être associé à un formulaire (cf 3.2.3.4). Cette classe permet d’utiliser un champ de texte au sein d’un formulaire. Les méthodes de la classe TextField sont répertoriées dans le tableau ci-dessous.

Méthode Description TextField(String label, String text, int maxSize, int constraints)

Constructeur permettant de créer un champ de texte en spécifiant l’intitulé, le contenu, la taille maximale et les contraintes de saisie.

String getString() void setString(String text)

Permet de lire et de modifier le contenu du champ de texte.

int size() Retourne le nombre de caractères contenus dans le champ de texte.

int getConstraints() void setConstraints(int constraints) Permet de lire et de modifier les contraintes de saisie.

int getMaxSize() int setMaxSize(int maxSize)

Permet de lire et de modifier le nombre de caractères maximal pouvant être contenus dans le champ.

Travail de diplôme Roggo Jean-Christophe

- 39 -

int getCaretPosition() Retourne la position du curseur dans le champ de texte.

void insert(char[] data, int offset, int length, int position) void insert(String src, int position)

Permet d’insèrer un tableau de caractères ou une chaîne de caractère dans le champ de texte à la position spécifiée.

void setChars(char[] data, int offset, int length)

Permet de remplacer une partie du contenu du champ de texte par le tableau de caractères spécifié.

void delete(int offset, int length) Permet de supprimer une partie du contenu du champ de texte.

int getChars(char[] data) Permet de copier le contenu du champ de texte dans un tableau de caractères.

Les méthodes héritées de la classe Item sont également disponibles.

La classe TextField comprend un certain nombre de constantes permettant de spécifier des contraintes de saisie. Le tableau ci-dessous contient une description pour chacune de ces constantes. Champ Description ANY L’utilisateur peut saisir n’importe quel texte. CONSTRAINT_MASK Masque de saisie. EMAILADDR L’utilisateur doit saisir une adresse e-mail. NUMERIC L’utilisateur doit saisir un nombre entier.

PASSWORD Les caractères saisis ne sont pas visibles à l’écran (pour la saisie d’un mot de passe).

PHONENUMBER L’utilisateur doit saisir un numéro de téléphone. URL L’utilisateur doit saisir une URL.

[DEL02][API] Ci-dessous vous trouverez une illustration du composant TextField mis en œuvre dans l’application testGUI (cf annexe n° 1).

3.2.3.7. La classe DateField

La classe DateField dérive de la classe Item (cf 3.2.3.3). Cette classe permet d’utiliser un champ de date et d’heure au sein d’un formulaire (cf 3.2.3.4). Le tableau suivant contient une description pour chacune des méthodes de la classe DateField [DEL02][API].

Travail de diplôme Roggo Jean-Christophe

- 40 -

Méthode Description DateField(String label, int mode, TimeZone timeZone) DateField(String label, int mode)

Constructeurs permettant de créer un champ de date en spécifiant la localisation ou pas.

Date getDate() Void setDate(Date date)

Permet de lire et de modifier la valeur du champ de date.

int getInputMode() void setInputMode(int mode)

Permet de lire et de modifier le mode du champ de date.

Les méthodes héritées de la classe Item sont également disponibles.

La classe DateField comprend trois constantes permettant de spécifier le mode du champ. Le mode indique la nature de l’information que l’utilisateur peut saisir. Le tableau ci-dessous contient une description pour chacun de ces modes [DEL02][API]. Champ Description DATE L’utilisateur ne peut saisir qu’une date. TIME L’utilisateur ne peut saisir qu’une heure. DATE_TIME L’utilisateur peut saisir la date et l’heure.

Ci-dessous vous trouverez une illustration du composant DateField mis en œuvre dans l’application testGUI (cf annexe n° 1).

3.2.3.8. La classe Gauge

La classe Gauge dérive également de la classe Item. Elle permet d’utiliser une jauge graphique au sein d’un formulaire. Ces méthodes sont recensées dans le tableau ci-dessous [DEL02][API]. Méthode Description Gauge(String label, boolean interactive, int maxValue, int initialValue)

Constructeur permettant de créer une jauge en spécifiant l’étiquette, le mode, la valeur maximale et la valeur initiale.

int getMaxValue() void setMaxValue(int maxValue) Permet de lire et de modifier la valeur maximale.

int getValue() void setValue(int value)

Permet de lire et de modifier la valeur courante de la jauge.

boolean isInteractive() Permet de savoir si la jauge est interactive ou non.

Travail de diplôme Roggo Jean-Christophe

- 41 -

Une jauge peut être interactive ou non. Dans le cas d’une jauge non interactive, seule l’application peut modifier sa valeur. Dans le cas d’une jauge interactive, l’utilisateur peut modifier sa valeur.

Ci-dessous vous trouverez une illustration du composant Gauge mis en œuvre dans l’application testGUI (cf annexe n° 1).

3.2.3.9. La classe ImageItem

ImageItem est une classe qui encapsule une instance de la classe Image (cf documentation fournie avec le J2ME Wireless Toolkit). Comme les autres composants associables à un formulaire, elle étend la classe abstraite Item. Grâce à cette classe, il est possible de spécifier la disposition d’une image associée à un formulaire. Pour cela, elle fournit les méthodes et champs décrits dans les tableaux ci-dessous [DEL02][API]. Méthode Description ImageItem(String label, Image img, int layout, String altText)

Constructeur prenant en paramètres l’étiquette, l’image, la disposition et le texte de remplacement.

String getAltText() void setAltText(String text)

Permet de lire et de modifier le texte de remplacement.

Image getImage() void setImage() Permet de lire et de modifier l’objet Image encapsulé.

int getLayout() void setLayout(int layout)

Permet de lire et de modifier la disposition de l’image dans le formulaire.

La classe ImageItem comprend un certain nombre de champs correspondant à des constantes qui spécifient la disposition du composant au sein d’un formulaire. Le tableau ci-dessous présente ces champs. Méthode Description LAYOUT_CENTER L’image est centrée horizontalement. LAYOUT_DEFAULT L’image est placée selon le positionnement par défaut. LAYOUT_LEFT L’image est cadrée à gauche. LAYOUT_RIGHT L’image est cadrée à droite. LAYOUT_NEWLINE_AFTER Une nouvelle ligne commence après l’image. LAYOUT_NEWLINE_BEFORE Une nouvelle ligne commence avant l’image.

Travail de diplôme Roggo Jean-Christophe

- 42 -

3.2.3.10. La classe StringItem

La classe StringItem encapsule une instance de la classe String. Elle dérive de la classe Item et permet d’associer du texte statique à un formulaire. Ces méthodes sont décrites dans le tableau ci-dessous [DEL02][API]. Méthode Description StringItem(String label, String text) Constructeur prenant l’étiquette et le contenu textuel

en paramètres. String getText() void setText(String text) Permet de lire et de modifier le contenu textuel.

3.2.3.11. La classe TextBox

La classe TextBox étend la classe abstraite Screen. Elle modélise un champ de saisie qui peut être affiché sans être contenu dans un formulaire. Son interface est très similaire à celle de la classe TextField (cf 3.2.3.6).

Ci-dessous vous trouverez une illustration du composant TextBox mis en œuvre dans l’application testGUI (cf annexe n° 1).

3.2.3.12. La classe Alert

La classe Alert étend la classe abstraite Screen. Elle modélise une boîte de dialogue affichant un message textuel, éventuellement accompagné d’une image ou d’un son. On l’utilisera volontiers pour afficher un avertissement, une erreur, une alarme … L’interface de cette classe est décrite dans le tableau ci-dessous. Méthode Description

Alert(String title) Alert(String title, String alertText, Image alertImage, AlertType alertType)

Constructeur permettant de créer une alerte en spécifiant son titre uniquement ou en spécifiant en plus son contenu textuel, son image associée et son type.

String getString() void setString(String str)

Permet de lire et de modifier le contenu textuel de l’alerte.

AlertType getType() void setType(AlertType type) Permet de lire et de modifier le type de l’alerte.

int getDefaultTimeout() Retourne la durée pendant laquelle l’alerte est affichée

Travail de diplôme Roggo Jean-Christophe

- 43 -

int getTimeout() void setTimeout(int time)

Permet de lire et de modifier la durée pendant laquelle l’alerte est affichée (en millisecondes).

Image getImage() void setImage(Image img)

Permet de lire et de modifier l’image associée à l’alerte.

La constante FOREVER définie dans la classe Alert permet de spécifier que l’alerte doit rester affichée tant que l’utilisateur n’a pas confirmé. L’instruction se présentera de la manière suivante : myAlert.setTimeout(Alert.FOREVER) ; La classe AlertType permet de donner une indication sur la nature de l’alerte. Elle comprend les constantes présentées dans le tableau ci-dessous. Méthode Description ALARM Permet de spécifier une alerte de type alarme. CONFIRMATION Permet de spécifier une alerte de type confirmation. ERROR Permet de spécifier une alerte de type erreur. INFO Permet de spécifier une alerte de type information. WARNING Permet de spécifier une alerte de type avertissement.

L’instruction ci-dessous permet de créer une alerte de type information (aucune image n’est associée à cette alerte). myAlert = new Alert(“Alerte INFO”, “***information***“, null, AlertType.INFO); A chaque type d’alerte est associé un son. La classe AlertType propose une méthode permettant d’utiliser ce son. L’instruction ci-dessous émet le son associé au type d’alerte INFO.

AlertType.INFO.playSound(myDisplay) ; [DEL02][API] Ci-dessous vous trouverez une illustration du composant Alert mis en œuvre dans l’application testGUI (cf annexe n° 1).

Travail de diplôme Roggo Jean-Christophe

- 44 -

3.2.3.13. La classe Ticker

La classe Ticker modélise un texte défilant continuellement sur l’affichage. Le composant Ticker peut être associé à toutes les classes héritant de la classe Displayable. Ces méthodes sont recensées dans le tableau ci-dessous [DEL02][API]. Méthode Description Ticker(String str) Constructeur permettant de spécifier le contenu

textuel du ticker. String getString() void setString(String str)

Permet de lire et de modifier le contenu textuel du ticker.

3.2.4. La gestion des évènements

La gestion des évènements au sein de l’interface utilisateur de haut niveau proposée par MIDP repose sur le principe de Source – Listener. L’API d’interface utilisateur de haut niveau comprend les classes et interfaces suivantes pour la gestion des évènements :

Command

CommandListener

ItemStateListener

3.2.4.1. La classe Command

La classe Command intègre des informations sémantiques sur une action. Cette classe permet de gérer la navigation parmi les écrans. Elle ne contient que le libellé de l’action, et non l’action elle-même. Cette action, déclenchée lors de l’activation de la commande se trouve dans l’objet implémentant l’interface CommandListener (cf 3.2.4.2) associé à l’écran. Une commande peut être associée à n’importe quel composant dérivant de la classe Displayable (cf 3.2.2.2). Le tableau ci-dessous répertorie les méthodes de la classe Command.

Méthode Description Command(String label, int commandType, int priority)

Constructeur permettant de spécifier le libellé, le type et le niveau de priorité de la commande.

int getCommandType() Permet de lire le type de la commande. String getLabel() Permet de lire le libellé de la commande. int getPriority() Permet de lire le niveau de priorité.

Une commande est caractérisée par un type. Le type permet de spécifier à quelle touche du terminal la commande va être associée. Par exemple, si sur un terminal, une commande d’annulation est habituellement associée à une touche spécifique, lorsqu’on utilise le type CANCEL pour une commande, celle-ci sera associée à cette même touche spécifique du terminal. Chacun des champs présentés dans le tableau ci-dessous correspond à un type.

Travail de diplôme Roggo Jean-Christophe

- 45 -

Champ Description BACK Type de commande retour. CANCEL Type de commande annulation. EXIT Type de commande quitter. HELP Type de commande aide. ITEM Type de commande item. OK Type de commande confirmation. SCREEN Type de commande écran. STOP Type de commande arrêter.

Une commande est également caractérisée par un niveau de priorité. Cette caractéristique permet de définir un niveau de priorité pour l’affichage des commandes sur l’écran du terminal. La priorité est définie par l’intermédiaire d’un entier, la plus haute priorité étant spécifiée par l’entier le plus petit. Le terminal organise la disposition des commandes d’abord en fonction du type de commande choisi, puis prend en compte les niveaux de priorité spécifiés. [DEL02][API]

3.2.4.2. L’interface commandListener

Cette interface définit le listener associé à un objet affichable (cf 3.2.2.2). Tout listener associé à un objet dérivant de la classe Displayable doit implémenter la méthode commandAction(Command c, Displayable d). C’est dans l’implémentation de cette méthode que l’on spécifiera l’action à entreprendre en fonction de la commande actionnée. L’échantillon de code ci-dessous tiré du MIDlet testGUI donne un exemple d’implémentation de cette méthode (cf annexe n° 1). public void commandAction (Command cmdSelected, Displayable d) { if (cmdSelected == cmdSortie) { destroyApp (false); } else if (cmdSelected == cmdRetour) { mainMenu(); } else { List l = (List) display.getCurrent(); switch (l.getSelectedIndex()) { case 0: testTextBox(); break; case 1: testAlert(); break; case 2: testForm(); break; } } }

Travail de diplôme Roggo Jean-Christophe

- 46 -

Les méthodes héritées de la classe Displayable par tous les composants affichables permettent d’ajouter des commandes et de mettre en place le listener (cf 3.2.2.2). [DEL02][API]

3.2.4.3. L’interface ItemStateListener

Cette interface définit le listener associé à un formulaire et à ces éléments (cf 3.2.3.4). Ce listener permettra de gérer les évènements intervenant sur les composants dérivant de la classe Item (cf 3.2.3.3). Tout listener de ce type doit obligatoirement implémenter la méthode itemStateChanged(Item item). Cette méthode est appelée lorsque l’état interne d’un composant Item a été modifié par l’utilisateur. Voici les différents cas possibles :

L’utilisateur modifie la valeur d’un composant Gauge (en mode interactif).

L’utilisateur modifie le contenu textuel d’un composant TextField.

L’utilisateur change de sélection dans un composant ChoiceGroup.

L’utilisateur modifie la date ou l’heure dans un composant DateField.

La méthode itemStateChanged(Item item) n’est appelée que lorsque l’utilisateur effectue une modification interactive de l’état interne d’un composant Item. Dans le cas où on modifie le contenu textuel d’un composant TextField (cf 3.2.3.6) via la méthode setString(String text), la méthode itemStateChanged(Item item) du listener n’est donc pas appelée.

Pour mettre en place un listener sur un formulaire, on utilisera la méthode setItemStateListener(ItemStateListener iListener) de la classe Form (cf 3.2.3.4). [DEL02][API]

Travail de diplôme Roggo Jean-Christophe

- 47 -

3.3. Le stockage persistant des données

Le stockage persistant des données consiste à stocker l’état des objets d’une application dans un emplacement non volatile de telle manière à ce que ces données soient conservées au delà de l’exécution de l’application. La section suivante traite du mécanisme de stockage persistant des données fourni par le profil MIDP : le RMS (Record Management System).

3.3.1. Le package RMS

Le package javax.microedition.rms contient les classes et interfaces permettant de gérer le stockage persistant des données. Les tableaux ci-dessous décrivent brièvement chacune de ces classes et interfaces. Classe Description RecordStore Implémente un RecordStore InvalidRecorIDException Exception déclenchée lorsque le recordID est invalide.

RecordStoreException Exception déclenchée lorsqu’une exception générale est survenue lors d’une opération sur un RecordStore.

RecordStoreFullException Exception déclenchée lorsque le système de fichier du RecordStore est plein.

RecordStoreNotFoundException Exception déclenchée lorsque le RecordStore spécifié est introuvable.

RecordStoreNotOpenException Exception déclenchée lorsqu’une opération est tentée sur un RecordStore fermé.

Interface Description RecordComparator Définit un comparateur d’enregistrements. RecordEnumeration Définit une énumération d’enregistrements. RecordFilter Définit un filtre d’enregistrements. RecordListener Définit un listener associé à un RecordStore.

[DEL02][API]

3.3.2. Le Record Store

Un Record Store comprend un ensemble d’enregistrements. Il peut être comparé à une table d’une base de donnée relationnelle. Chaque enregistrement d’un Record Store est désigné par un identifiant. On parle alors d’ID d’enregistrement (recordID). Cet ID d’enregistrement, un nombre entier, correspond à la clé primaire des enregistrements. Cette valeur vaut 1 pour le premier enregistrement du Record Store et sera incrémentée de 1 à chaque nouvel enregistrement. Le nom d’un Record Store est sensible à la casse et est limité à 32 caractères. Un MIDlet ne peut pas créer deux Record Store de même nom dans une même application. Deux Record Store peuvent en revanche avoir le même nom si ils sont utilisés dans des applications distinctes. Afin d’éviter toute corruption des données due à des accès concurrents, les opérations de lecture ou d’écriture verrouillent le Record Store jusqu’à ce qu’elles soient terminées. Cependant, dans le cas où plusieurs threads accèdent à un Record Store, il est à la charge du développeur de synchroniser ces accès. En

Travail de diplôme Roggo Jean-Christophe

- 48 -

effet, si deux threads différents veulent modifier un enregistrement du Record Store au même moment, les opérations sont sérialisées correctement par le RMS, mais au final, l’une des écritures écrasera l’autre ce qui risque de causer des problèmes au sein du MIDlet. L’espace disponible pour le stockage persistant diffère d’un terminal à l’autre. Pour les téléphones mobiles compatibles MIDP existants sur le marché à l’heure actuelle, l’espace de stockage disponible pour l’ensemble des applications installées ne dépasse que rarement les 500 Ko. Pour le Sony Ericsson t610, par exemple, chaque application dispose d’un espace de stockage d’environ 30 Ko et le total de mémoire de stockage disponible pour les Record Store de toutes les applications installées est d’environ 500 Ko (cf 4.2.1).

3.3.2.1. La classe RecordStore

Cette classe modélise un Record Store. Ces méthodes permettent d’effectuer les opérations de base comme l’ouverture, la fermeture, la création, la modification ou la suppression du Record Store. Le tableau ci-dessous décrit l’ensemble de ces méthodes. Méthode Description static RecordStore openRecordStore(String recordStoreName, boolean createIfNecessary)

Méthode statique permettant d’ouvrir un Record Store (si le paramètre createIfNecessary est vrai, le Record Store est créé s’il n’existe pas déjà).

void closeRecordStore() Permet de fermer un Record Store. static void deleteRecordStore(String recordStoreName Permet de supprimer un Record Store.

String getName() Retourne le nom du Record Store. static String[] listRecordStores() Retourne la liste des Record Store du MIDlet. RecordEnumeration enumarateRecords(RecordFilter filter, RecordComparator comparator, boolean keepUpdated)

Retourne une énumération des enregistrements selon le filtre et l’ordre de tri spécifié.

int addRecord(byte[] data, int offset, int numBytes)

Permet d’ajouter un enregistrement dans un Record Store à partir d’un tableau d’octets. Une fois l’enregistrement ajouté, son ID est retourné.

void setRecord(int recordId, byte[] newData, int offset, int numBytes)

Permet de modifier l’enregistrement spécifié par le paramètre recordId.

byte[] getRecord(int recordId) Retourne, sous forme de tableau d’octets, une copie de l’enregistrement spécifié par le paramètre recordId.

int getRecord(int recordId, byte[] buffer, int offset)

Permet d’obtenir les données contenues dans l’enregistrement spécifié (la méthode retourne le nombre d’octets copiés dans buffer).

void deleteRecord(int recordId) Permet de supprimer l’enregistrement spécifié.

int getNextRecordID() Retourne l’identifiant du prochain enregistrement qui sera ajouté au Record Store.

int getNumRecords() Retourne le nombre d’enregistrements contenus dans le Record Store.

void setRecordListener(RecordListener listener) void removeRecordListener(RecordListener listener)

Permet de mettre en place et de supprimer le listener associé au Record Store.

int getRecordSize(int recordId) Retourne la taille en octets de l’enregistrement. int getSize() Retourne la taille totale en octets du Record Store.

int getSizeAvailable() Retourne l’espace de stockage courant disponible pour le Record Store (en octets).

long getLastModified() Retourne l’heure de la dernière modification du Record Store selon le format spécifié par System.currentTimeMillis().

int getVersion() Retourne le numéro de version du Record Store (à chaque fois qu’un Record Store est modifié son numéro de version est automatiquement incrémenté).

Travail de diplôme Roggo Jean-Christophe

- 49 -

Pour créer des Record Store multi-colonnes, le développeur devra inclure des séparateurs au sein de l’enregistrement et implémenter le parser adéquat pour récupérer les différentes informations correctement. En utilisant plusieurs Record Store le développeur pourra implémenter un semblant de base de données relationnelle. [DEL02][API]

3.3.2.2. L’interface RecordComparator

Cette interface définit un comparateur d’enregistrements. On implémentera volontiers l’interface RecordComparator pour effectuer un tri sur les enregistrements d’un Record Store. La méthode suivante devra être implémentée : int compare(byte[] rec1, byte[] rec2)

Outre cette méthode, l’interface définit également les trois constantes décrites dans le tableau ci-dessous. Champ Description

FOLLOWS Constante retournée par la méthode de comparaison lorsque le résultat de la comparaison est : rec1 > rec2 (la valeur de la constante est 1).

PRECEDES Constante retournée par la méthode de comparaison lorsque le résultat de la comparaison est : rec1 < rec2 (la valeur de la constante est –1).

EQUIVALENT Constante retournée par la méthode de comparaison lorsque le résultat de la comparaison est : rec1 = rec2 (la valeur de la constante est 0).

[DEL02][API]

3.3.2.3. L’interface RecordFilter

Cette interface définit un outil de filtrage des enregistrements. On implémentera cette interface pour filtrer les enregistrements en fonction du critère choisi. La méthode suivante devra être implémentée : boolean matches(byte[] candidate) [DEL02][API]

3.3.2.4. L’interface RecordEnumeration

Cette interface définit une énumération d’enregistrements bidirectionnelle. On l’utilisera volontiers pour extraire les enregistrements d’un Record Store selon un

Travail de diplôme Roggo Jean-Christophe

- 50 -

ordre différent que leur ordre d’insertion. Ses méthodes sont décrites dans le tableau ci-dessous. Méthode Description int previousRecordId() int nextRecordId()

Permet de retourner l’ID de l’enregistrement précédent et de l’enregistrement suivant.

boolean hasPreviousElement() boolean hasNextElement()

Permet de savoir si il existe un enregistrement précédent et un enregistrement suivant.

byte[] previousRecord() byte[] nextRecord()

Retourne l’enregistrement précédent et l’enregistrement suivant.

int numRecords() Retourne le nombre d’enregistrements.

void keepUpdated(boolean keepUpdated) Permet d’indiquer si l’énumération des enregistrements doit être actualisée pour refléter les modifications sur les enregistrements.

boolean isKeptUpdated() Retourne vrai si l’énumération est actualisée automatiquement lors de modifications sur les enregistrements.

void rebuild() Permet d’actualiser manuellement l’énumération.

void destroy() Permet de libérer les ressources utilisées par l’énumération d’enregistrements.

void reset() Permet de mettre l’énumération dans l’état où elle était au moment de sa création.

[DEL02][API]

3.3.2.5. L’interface RecordListener

L’interface RecordListener définit le listener associé à un composant RecordStore. Ce listener permet la supervision des modifications des enregistrements qui consiste à être averti lorsqu’un ajout, une modification ou une suppression sont effectués sur un enregistrement. L’interface RecordListener définit les trois méthodes décrites dans le tableau ci-dessous correpondant chacune à un événement. Méthode Description void recordAdded(RecordStore recordStore, int recordId)

Méthode exécutée lorsqu’un enregistrement est ajouté au Record Store.

void recordChanged(RecordStore recordStore, int recordId)

Méthode exécutée lorsqu’un enregistrement du Record Store est modifié.

void recordDeleted(RecordStore recordStore, int recordId)

Méthode exécutée lorsqu’un enregistrement du Record Store est supprimé.

[DEL02][API] Vous trouverez dans l’annexe n°2 un exemple de mise en œuvre des composants de RMS.

Travail de diplôme Roggo Jean-Christophe

- 51 -

Cette quatrième partie débute par une brève présentation des différents outils que j’ai utilisés lors de mes tests. L’étude d’un MIDlet permettant de convertir des devises en utilisant un Web Service sera ensuite abordée.

4. J2ME en pratique

4.1. Les outils

Comme nous l’avions exposé dans la troisième partie de ce dossier, le cycle de développement d’un MIDlet est constitué de cinq étapes chacune nécessitant l’utilisation d’outil(s). Le tableau ci-dessous indique quels outils j’ai choisis pour réaliser chacune de ces étapes dans mes développements : Etape Outil(s)

Ecriture de l’application avec les API de MIDP. L’environnement de développement J2ME Wireless Toolkit 2.1 et l’éditeur de texte Edit+

Compilation et prévérification de l’application. L’environnement de développement J2ME Wireless Toolkit 2.1

Test de l’application avec un émulateur L’environnement de développement J2ME Wireless Toolkit 2.1

Packaging de l’application. L’environnement de développement J2ME Wireless Toolkit 2.1

Test de l’application packagée sur le terminal mobile.

Clé USB Bluetooth MITSUMI BLUETOOTH USB ADAPTATOR et téléphone mobile Sony Erisson t610

4.1.1. L’environnement de développement

Mon choix s’est arrêté sur le J2ME Wireless Toolkit pour des raisons pratiques avant tout. En effet, l’environnement de Sun Microsystem est téléchargeable gratuitement et s’avère simple et efficace. Beaucoup d’autres environnements de développement J2ME existent sur le marché, souvent proposés sous forme de plug-in. Vous trouverez quelques références dans le tableau ci-dessous. Environnement Description

MobileSet Plug-In Plug-In pour Borland JBuilder

Visual Age Micro Edition Plug-In pour IBM WebSphere Studio

Visual Age Micro Edition Plug-In pour l’IDE d’Oracle, JDevelopper

EclipseMe Plug-In Plug-In pour l’environnement open source Eclipse

Pour plus de détails sur ces environnements consultez l’adresse suivante : http://www.microjava.com/articles/techtalk/ide

Travail de diplôme Roggo Jean-Christophe

- 52 -

4.1.1.1. J2ME Wireless Toolkit 2.1

L’installation du J2ME Wireless Toolkit est une formalité (les fichiers d’installation sont disponibles sur le cd rom fourni en annexe). Une fois l’environnement installé, le menu de la figure ci-dessous est disponible.

La première rubrique vous permet de sélectionner un émulateur par défaut. La seconde rubrique vous donne accès à la documentation de l’environnement ainsi qu’à celle des API (Application Program Interface). La rubrique suivante permet de lancer la console pour créer et gérer des projets. La quatrième rubrique lance un outil d’assistance au transfert de fichier sur le terminal cible via une connexion OTA (Over The Air). La rubrique suivante vous permet de configurer les émulateurs. La sixième rubrique permet d’exécuter une application J2ME dans l’émulateur (les fichiers exécutables par l’émulateur sont les fichiers *.jad). La dernière rubrique quant à elle donne accès à un utilitaire de configuration. La console du J2ME Wireless Toolkit (Ktoolbar) est illustrée ci-dessous.

Travail de diplôme Roggo Jean-Christophe

- 53 -

La console est le cœur de l’environnement de développement. Elle est utilisée pour créer, gérer, compiler et packager les projets. En sélectionnant la rubrique Settings de la console vous pourrez, entre autres, définir la configuration et le profil J2ME, comme l’illustre l’image ci-dessous.

Lorsqu’un projet est créé, un dossier portant le nom du projet est ajouté dans le répertoire apps situé à la racine du dossier d’installation. Le dossier de projet contient les quatre répertoires décrits dans le tableau ci-dessous. Dossier Description

%WTK21/apps/nom_projet/bin Contient le fichier *.jar, *.jad et le fichier manifest (cf 3.1.2)

%WTK21/apps/nom_projet/classes Contient les classes compilées

%WTK21/apps/nom_projet/lib Contient les bibliothèques utiles à l’application

%WTK21/apps/nom_projet/res Contient les ressources utiles à l’application (des images au format *.png par exemple)

%WTK21/apps/nom_projet/src Contient les sources des classes

Travail de diplôme Roggo Jean-Christophe

- 54 -

Le J2ME Wireless Toolkit ne propose pas d’éditeur de texte pour écrire le code source des applications. Le développeur utilisera son éditeur de texte préféré pour écrire les fichiers sources puis ajoutera ces derniers au répertoire src du projet. La rubrique Create Package du menu illustré ci-dessous permet de générer le fichier *.jar destiné au terminal mobile cible et le fichier *.jad destiné à l’émulateur.

Pour tester les applications fournies sur le cd rom annexé à ce dossier dans l’émulateur du J2ME Wireless Toolkit, il suffit d’effectuer les étapes suivantes :

Installer le J2ME Wireless Toolkit 2.1

Coller les répertoires correspondant à chaque projet dans le dossier app situé à la racine du répertoire d’installation

Lancer la console KToolbar

Ouvrir le projet de votre choix

Sélectionner le bouton Run de la console KToolbar

Pour obtenir des informations plus détaillées sur l’utilisation du J2ME Wireless Toolkit 2.1, veuillez vous référer à la documentation fournie avec l’outil.

Travail de diplôme Roggo Jean-Christophe

- 55 -

4.1.2. Le terminal mobile cible

Toutes les applications fournies sur le cd rom en annexe ont été testées et s’exécutent correctement sur le téléphone mobile Sony Ericsson t610. Dans le cas ou vous voudriez tester ces applications sur un autre terminal, veuillez consulter l’adresse suivante qui vous donnera des informations quant à la compatibilité du terminal avec la technologie J2ME : http://jal.sun.com/webapps/device/device Toutes les applications proposées sur le cd rom annexé sont destinées à des terminaux mobiles J2ME compatibles avec la configuration CLDC 1.0 et le profil MIDP 1.0. Le terminal cible sur lequel ces applications seront testées devra donc obligatoirement implémenter cette configuration et ce profil (ou les versions ultérieures, à savoir CLDC 1.1 et MIDP 2.0).

4.1.2.1. Le terminal mobile Sony Ericsson t610

[SEW] Comme spécifié dans le tableau ci-dessus, le t610 implémente la configuration CLDC 1.0, le profil MIDP 1.0 et le package optionnel MMAPI. Le tableau suivant donne des informations détaillées concernant la mémoire disponible pour l’exécution des applications J2ME.

[SEJ]

Réseaux 900/1800/1900 GPRS

Résolution de l’affichage 128 x 160

Nb couleurs 65536

Java CLDC 1.0/MIDP 1.0/MMAPI

Micronavigateur WAP 2.0 (WML, xHTML)

Messagerie SMS/EMS/MMS

Connectivité Bluetooth/Infrarouge/SyncML

Mémoire ~2 MB

Mémoire de stockage RMS totale 500 KB

Mémoire de stockage RMS par application 30 KB

Taille du heap Java 256 KB

Taille du heap natif utilisé pour les composants GUI

~150 KB

RAM vidéo native disponible pour Java ~80 KB

Travail de diplôme Roggo Jean-Christophe

- 56 -

Pour obtenir plus d’informations concernant ce terminal mobile, vous êtes invités à consulter les documents suivants que vous trouverez sur le cd rom fourni en annexe :

wp_t610_r2a.pdf

dg_j2me_midp1_r3a.pdf

Sony Ericsson propose un site offrant toutes les informations nécessaires au développement d’applications J2ME pour les différents modèles de la marque (exemples d’applications, forum …). L’adresse suivante vous permettra d’accéder à ces informations gratuitement : http://developer.sonyericsson.com/site/global/home/p_home.jsp Notons également que Sony Ericsson distribue gratuitement sa propre version de l’environnement J2ME Wireless Toolkit accompagnées d’émulateurs configurés de telle manière à recréer l’apparence et le comportement de ses différents modèles de téléphones. Les fichiers nécessaires à l’installation de l’environnement SonyEricsson J2ME SDK 2.1.4 beta sont disponibles sur le cd rom annexé. Remarque : sur le terminal mobile t610 en particulier, pour qu’un MIDlet utilisant un composant de connexion HttpConnection s’exécute correctement, il est nécessaire de configurer un nouveau profil d’accès Internet général. Si le profil WAP par défaut est utilisé, le MIDlet ne pourra pas ouvrir de connexion HTTP. Pour configurer un nouveau profil d’accès Internet général, consultez la documentation du téléphone et renseignez vous auprès de votre opérateur téléphonique.

4.1.3. L’outil de transfert de l’application

Une fois l’application packagée grâce à l’environnement de développement (cf 4.1.1), elle peut être installée sur le terminal cible. Le transfert de l’application packagée depuis la station de développement vers le terminal cible peut être effectué de différentes manières. Soit le fichier *.jar est stocké sur un serveur et le terminal cible le télécharge via un navigateur WAP, soit le fichier est transféré grâce à une connexion directe entre la station de développement et le terminal cible. La première solution nécessite que le terminal soit muni d’un navigateur WAP, ce qui est le cas de la plupart des téléphones mobiles compatibles CLDC 1.0 et MIDP 1.0. On utilisera donc volontiers cette solution pour distribuer des MIDlets à grande échelle. La seconde solution nécessite le concours d’un service de transfert de fichiers via une connexion par câble ou une connexion OTA (Over The Air). Tous les MIDlet disponibles sur le cd rom annexé ont été transférés via Bluetooth pour être testés sur le terminal cible. Le service de transfert de fichier OBEX (Object Exchange) supporté par le terminal cible Sony Ericsson t610 (cf 4.2.1) et la clé USB (Universal Serial Bus) Bluetooth du fabricant MITSUMI installée sur la station de développement ont permis de mettre en œuvre la connexion OTA.

Travail de diplôme Roggo Jean-Christophe

- 57 -

4.2. L’application CurrencyConverter

Sur le cd rom fourni en annexe, vous trouverez l’application CurrencyConverter. Pour pouvoir exécuter cette application dans l’émulateur du J2ME Wireless Toolkit, référez vous au point 4.1.1.1 de la présente étude. Ce prototype d’application, destiné à la configuration CLDC 1.0 et au profil MIDP 1.0, permet de convertir des devises par l’intermédiaire d’un serveur PHP (Personal Home Page). Dans ce cas précis, l’application J2ME s’exécutant sur le terminal mobile s’apparente à un client léger (cf Gartner Model). En effet, le MIDlet CurrencyConverter envoie une requête HTTP GET à un serveur PHP qui se chargera d’effectuer un appel SOAP (Simple Objetc Access Protocol) RPC (Remote Procedure Call) sur un autre serveur pour obtenir un service. Une fois le service rendu, le serveur PHP effectue un calcul, puis renvoie le résultat à l’application J2ME. Le schéma ci-dessous illustre cette architecture distribuée.

SOAP RPC

HTTP GET

Serveur PHP

ClientJ2ME

Serveur de Web Services

Travail de diplôme Roggo Jean-Christophe

- 58 -

L’avantage de cette architecture est que le terminal mobile profite des ressources de deux parties tierces. En effet, aucun calcul n’est effectué sur le terminal. Le désavantage principal réside dans le fait que le bon fonctionnement de l’application dépend en grande partie des deux serveurs impliqués. Si un de ces serveurs tombe en panne, aucune conversion ne pourra être effectuée. Pour résoudre ce problème, on pourrait stocker un jeu limité d’information sur le terminal client (cf 3.3) de telle sorte à pouvoir, si nécessaire, exécuter l’application de manière totalement autonome. Une autre solution consisterait à éliminer une de ces tierces parties en utilisant le package kSOAP, librairie permettant l’invocation de Web Service au sein d’une application J2ME. Pour obtenir plus d’informations concernant ce package et son utilisation veuillez vous référer aux adresses suivantes : http://ksoap.objectweb.org/ http://www.sys-con.com/story/?storyid=37193&DE=1 http://webservices.xml.com/lpt/a/ws/2003/08/19/ksoap.html http://www.capescience.com/articles/wireless/index.shtml http://www.javaworld.com/javaworld/jw-08-2002/jw-0823-wireless.html http://wirelessadvisor.net/doc/12697 Il faut toutefois être conscient du fait que l’utilisation d’un tel package augmente considérablement la taille du fichier *.jar à destination du terminal mobile. Avec l’architecture actuelle, l’application CurrencyConverter, une fois packagée, occupe un espace mémoire d’environ 5 ko. Si le package kSOAP avait été utilisé, la taille de l’application packagée aurait atteint environ 50 Ko.

4.2.1. Le client J2ME

Le code source du client J2ME est disponible dans le répertoire du projet CurrencyConverter fourni sur le cd rom annexé. Ce prototype comporte deux classes, l’une responsable de la gestion de l’interface utilisateur (cf Converter.java) et l’autre responsable de l’interaction réseau avec le serveur PHP (cf NetworkInteraction.java).

La classe responsable de l’interaction réseau implémente l’interface Runnable [API], ce qui permet de mettre en œuvre la connexion réseau dans un autre thread (processus) que celui où est géré l’interface utilisateur. Si ces deux mécanismes étaient implantés dans le même thread, l’exécution de l’application pourrait aboutir à un dead-lock (verrou mortel). La classe responsable de la gestion de l’interface graphique utilise plusieurs composants GUI haut niveau de MIDP pour permettre à l’utilisateur de saisir les différentes informations de conversion.

Travail de diplôme Roggo Jean-Christophe

- 59 -

Ci-dessous vous trouverez quelques illustrations de l’application CurrencyConverter exécutée sur l’émulateur du J2ME Wireless Toolkit.

Lorsque l’application démarre, l’écran de saisie de la Fig. 1 s’affiche. Cet écran permet à l’utilisateur de saisir la valeur à convertir dans un champ de texte n’acceptant que des nombres entiers (une contrainte de saisie est spécifiée à l’instanciation de la classe TextField cf 3.2.3.6). Les deux liste de choix invitent l’utilisateur à sélectionner une devise source et une devise de destination (Fig. 1 et Fig. 2). Une fois la commande Convertir activée par l’utilisateur, l’écran de sécurité de la Fig. 3 s’affiche. Le message témoignant du succès de l’interaction s’affiche quelques secondes après l’acceptation de l’utilisateur (Fig. 4). Une fois que l’utilisateur a confirmé, le résultat de la conversion s’affiche enfin (Fig. 5). Si l’utilisateur refuse que l’application utilise le réseau (Fig. 3), l’écran de la Fig. 6 s’affiche. Le refus de l’utilisateur est valable pour toute la durée d’exécution de l’application. Pour effectuer une conversion, il faudra donc quitter l’application, puis la relancer.

Fig. 1 Le champ de texte et la liste de monnaies source

Fig. 2 La liste des monnaies de destination

Fig. 3 L’écran de sécurité

Fig. 4 Le message témoignant du succès de l’interaction

Fig. 5 Le résultat de la conversion

Fig. 6 Le message d’erreur témoignant d’un refus d’accès

Travail de diplôme Roggo Jean-Christophe

- 60 -

L’application CurrencyConverter n’effectue aucun calcul pour réaliser la conversion, cette tâche est assurée par le serveur PHP avec lequel elle communique.

4.2.2. Le serveur PHP

Le code source du script PHP exécuté sur le serveur est disponible sur le cd rom fourni en annexe. La librairie nuSOAP est utilisée pour effectuer l’appel au Web Service. Une fois le taux de la devise retourné, le serveur PHP convertit la valeur que le client J2ME lui a fournie, puis, lui renvoie le résultat. L’appel de Web Service depuis un script PHP n’est pas directement l’objet de la présente étude. Pour obtenir plus d’informations sur ce sujet, vous pouvez consulter l’adresse suivante : http://csproject.it.bton.ac.uk/sdh1/swm35/postcourse/2.php

4.2.3. Le Web service

Le Web Service invoqué depuis le serveur PHP est fourni par XMETHODS. Il retourne le taux de conversion d’une devise par rapport à une autre. Toutes les informations nécessaires concernant le Web Service Currency Exchange Rate sont disponibles à l’adresse suivante : http://www.xmethods.com/ve2/ViewListing.po;jsessionid=9Oq5HRbo5fbf8-Xwns4SKOn3(QHyMHiRM)?key=uuid:D784C184-99B2-DA25-ED45-3665D11A12E5 Remarque : étant donné que l’architecture de ce prototype implique deux serveurs tiers, il n’est pas garantit que vous puissiez tester ce prototype à tout moment. En effet, le serveur de Web Service est normalement fiable mais il se peut qu’il ne réponde pas si il est surchargé (le prototype ne gère pas ce cas de figure). D’autre part, le serveur PHP n’est pas en activité 24h/24h.

Travail de diplôme Roggo Jean-Christophe

- 61 -

5. Conclusion

L’explosion du marché des terminaux mobiles et la popularité du langage Java justifient que les développeurs s’intéressent à une technologie comme J2ME. Par ailleurs, l’architecture modulaire caractérisant la technologie de Sun Microsystems est parfaitement adaptée aux différents types de terminaux mobiles et à leur évolution technologique perpétuelle. J2ME, comme les autres technologies Java, comporte l’avantage notoire de la portabilité (Write Once And Run Everywhere). Une même application peut être exécutée sur un téléphone portable ou sur un PDA PocketPC (des tests de dernière minute qui n’ont malheureusement pas pu être intégrés à la présente étude me permettent de le confirmer). La portabilité des applications J2ME est un argument de force face à des technologies concurrentes comme celle de Microsoft (Microsoft Embedded Architecture), qui se concentre sur un unique environnement mobile, Windows CE. D’autre part, la collaboration intensive de Sun Microsystem avec des fabricants de terminaux mobiles tels que Motorola, Nokia, Sony Ericsson ou Siemens facilite l’évolution de la technologie en fonction des terminaux cibles. Notons également que Sun propose des outils simples et efficaces pour assurer le cycle de développement d’une application. Les émulateurs proposés facilitent les tests, mais il est toutefois conseillé de tester les applications sur le terminal cible pour se faire une idée exacte du résultat. Les terminaux mobiles disposent de ressources limitées. Les limitations se rapportant à la puissance de calcul ou à l’espace de stockage peuvent être contournées grâce à une architecture distrbuée (utilisation de Web Services, stockage de données sur un serveur …). Seules les contraintes d’affichage limitent réellement les possibilités de développement.

Travail de diplôme Roggo Jean-Christophe

- 62 -

Bibliographie Livre [DEL02] : Bruno Delb J2ME Applications Java pour terminaux mobiles EYROLLES 2002 ISBN 2-212-11084-7 Sites [WJS04] : Wireless Java Sun Microsystem http://wireless.java.sun.com/ [JSU04] : Java Sun J2ME

http://java.sun.com/j2me/ [DSU04] : Introduction Mobility Java Technology http://developers.sun.com/techtopics/mobility/getstart/

Articles [JNE04] : Le Journal du Net Le marché des terminaux mobile s’envole 06/2004 http://www.journaldunet.com/0406/040602nokia.shtml [MVE02] : Electronique Les machines Java pour l’embarqué 06/2002 http://www.electronique.biz/Pdf/ELM200206010126100.pdf Documentation [API] : Documentation des API J2ME Fournie avec le J2ME Wireless Toolkit [SEW] : Sony Ericsson t610 White paper Fournie sur le cd rom annexé wp_t610_r2a.pdf [SEJ] : Java Support in Sony Ericsson mobiles phones Fournie sur le cd rom annexé

dg_j2me_midp1_r3a.pdf

Travail de diplôme - annexe n°1 Roggo Jean-Christophe

- 1 -

Annexe n°1 : API d’interface utilisateur haut niveau

L’application testGUI est un exemple de mise en œuvre de la plupart des composants de l’API d’interface utilisateur haut niveau fournie par le profil MIDP.

import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import java.io.*; public class TestGUI extends MIDlet implements CommandListener { // Déclaration du gestionnaire d'affichage private Display display = null; // Déclaration d'un composant List qui fera office de menu private List myMenu = null; // Déclaration d'un composant Image private Image myImg = null; // Déclaration d'une autre image private Image myImgMenu1 = null; // Déclaration d'une autre image private Image myImgMenu2 = null; // Déclaration d'une autre image private Image myImgMenu3 = null; // Déclaration d'une zone de texte statique private StringItem myStringItem = null; // Déclaration de la liste de choix private ChoiceGroup myChoiceGroup = null; // Déclaration de la zone de texte private TextBox myTextbox = null; // Déclaration d'un ticker private Ticker myTicker = null; // Déclaration de l'alerte private Alert myAlert = null; // Déclaration d'un composant date private DateField myDate = null; // Déclaration d'un composant formulaire private Form myForm = null; // Déclaration d'un composant jauge private Gauge myGauge = null; // Déclaration d'un champ de texte private TextField myTextfield = null; // Déclaration et création des commandes retour, menu et sortie static final Command cmdRetour = new Command ("Retour", Command.BACK, 0); static final Command cmdSortie = new Command ("Sortie", Command.EXIT, 1); // Les sources des images static final String sourceImg = "/duke.png"; static final String sourceImgMenu1 = "/redSquare.png"; static final String sourceImgMenu2 = "/greenSquare.png"; static final String sourceImgMenu3 = "/blueSquare.png"; /** * Constructeur **/ public TestGUI() { // Création du menu myMenu = new List ("Test GUI", Choice.IMPLICIT); // Création de toutes les images try { myImgMenu1 = Image.createImage(sourceImgMenu1); myImgMenu2 = Image.createImage(sourceImgMenu2); myImgMenu3 = Image.createImage(sourceImgMenu3); myImg = Image.createImage(sourceImg);

Travail de diplôme - annexe n°1 Roggo Jean-Christophe

- 2 -

} catch (IOException e){ e.printStackTrace(); } // Ajouts des éléments au menu myMenu.append ("Test TextBox", myImgMenu1); myMenu.append ("Test Alert", myImgMenu2); myMenu.append ("Test Form", myImgMenu3); // Ajout de la commande sortie au menu myMenu.addCommand (cmdSortie); // Mise en place du listener myMenu.setCommandListener (this); // Création du ticker myTicker = new Ticker ("Test de l'interface graphique haut niveau."); // Association du ticker au menu myMenu.setTicker (myTicker); // Création d'un composant DateField myDate = new DateField ("La date d'ajourd'hui : ", DateField.DATE); // Obtention de la date courante et assignation au composant DateField java.util.Date now = new java.util.Date(); myDate.setDate (now); // Création d'un composant jauge myGauge = new Gauge("Jauge", true, 10, 0); // Création d'un composant champ de texte qui sera associé à un formulaire myTextfield = new TextField("Champ de texte", "", 50, TextField.ANY); // Création d'une liste de choix (à choix exclusif) myChoiceGroup = new ChoiceGroup ("Faites votre choix :", myChoiceGroup.EXCLUSIVE); // Ajout des éléments de la liste de choix myChoiceGroup.append ("Option 1", null); myChoiceGroup.append ("Option 2", null); myChoiceGroup.append ("Option 3", null); // Création de la zone de texte statique myStringItem = new StringItem ("Une image :", ""); // Création d'un composant formulaire myForm = new Form ("Formulaire"); // Association du champ de texte, de la date, de la jauge, de la liste de choix, // de la zone de texte statique et de l'image au formulaire myForm.append (myTextfield); myForm.append (myDate); myForm.append (myGauge); myForm.append(myChoiceGroup); myForm.append (myStringItem); myForm.append (new ImageItem(null, myImg, ImageItem.LAYOUT_CENTER, null)); // Ajout d'une commande de retour myForm.addCommand (cmdRetour); // Mise en place du listener myForm.setCommandListener (this); // Création d'une zone de texte de taille 50 avec le libellé // "Saisissez votre texte :". La contrainte de saisie ANY est spécifiée ce qui signifie // que l'utilisateur pourra saisir n'importe quel caractère. myTextbox = new TextBox ("Saisir du texte :", "", 50, TextField.ANY); // Ajout de la commande de retour au TextBox myTextbox.addCommand (cmdRetour); // Mise en place du listener myTextbox.setCommandListener (this); // Création d'une alerte de type INFO myAlert = new Alert ("Une alerte sonore"); myAlert.setType (AlertType.INFO); // Cette alerte reste affichée tant que l'utilisateur ne fait pas de confirmation myAlert.setTimeout(Alert.FOREVER); myAlert.setString ("Alerte de type INFO."); }

Travail de diplôme - annexe n°1 Roggo Jean-Christophe

- 3 -

/** * Lance le MIDlet. **/ public void startApp() throws MIDletStateChangeException { display = Display.getDisplay (this); mainMenu(); } /** * Suspend le MIDlet **/ public void pauseApp() { } /** * Termine l'exécution du MIDlet **/ public void destroyApp (boolean unconditional) { notifyDestroyed(); } /** * Affichage du menu principal **/ private void mainMenu() { // Affichage du menu principal display.setCurrent(myMenu); } /** * Test du composant TextBox **/ private void testTextBox() { // Affichage du composant TextBox display.setCurrent (myTextbox); } /** * Test du composant Alert **/ public void testAlert() { // Affichage de l'alerte display.setCurrent (myAlert); } /** * Test du composant Form **/ public void testForm() { // Affichage du composant formulaire et de ces éléments associés display.setCurrent (myForm); }

Travail de diplôme - annexe n°1 Roggo Jean-Christophe

- 4 -

/** * Gestion des événements **/ public void commandAction (Command cmdSelected, Displayable d) { // Si la commande Sortie est activée, on quitte le MIDlet. if (cmdSelected == cmdSortie) { destroyApp (false); } else if (cmdSelected == cmdRetour) { // Si la commande Retour est activée, on retourne au menu. mainMenu(); } else { // Dans les autres cas, il s'agit forcément de la sélection d'un élément // du menu. On lit la position de l'élément sélectionné dans la liste // et on appelle la méthode correspondante. List l = (List) display.getCurrent(); switch (l.getSelectedIndex()) { case 0: testTextBox(); break; case 1: testAlert(); break; case 2: testForm(); break; } } } }

Vous trouverez ci-dessous quelques illustrations de l’application testGUI exécutée sur l’émulateur standard du J2ME Wireless Toolkit 2.1.

Fig. 1 Ecran de démarrage de l’application testGUI

Fig. 2 Menu implémenté par la classe List

Fig. 3 Champ de texte implémenté par la classe TextBox

Travail de diplôme - annexe n°1 Roggo Jean-Christophe

- 5 -

Une fois l’application lancée le menu illustré à la Fig. 2 s’affiche. Si l’utilisateur choisi Test TextBox le champ de texte illustré à la Fig. 3 s’affiche. La commande Retour permet de revenir au menu. Lorsque l’utilisateur choisit Test Alert, l’alerte illustrée à la Fig. 4 s’affiche. Une fois que l’utilisateur a confirmé, le menu s’affiche à nouveau. Si l’utilisateur choisit Test Form le formulaire et ses composants associés illustrés à la Fig. 5 et Fig. 6 s’affichent. Lorsque l’utilisateur veut saisir une nouvelle date dans le champ de date l’écran de la Fig. 5 s’affiche.

Fig. 4 Alerte de type INFO implémentée par la classe Alert

Fig. 5 Formulaire avec des composants TextField, DateField, Gauge …

Fig. 6 Suite du formulaire avec les composants ChoiceGroup et Image

Fig. 5 Ecran de saisie de la date du composant DateField

Travail de diplôme - annexe n°2 Roggo Jean-Christophe

- 1 -

Annexe n°2 : Mise en œuvre de RMS

L’application testRecordStore est un exemple de mise en œuvre du RMS (Record Management System). Son code source est présenté dans l’encadré ci-dessous.

import javax.microedition.midlet.*; import javax.microedition.lcdui.*; import javax.microedition.rms.*; // Le MIDlet implémente les interfaces CommandListener et RecordListener public class TestRec extends MIDlet implements CommandListener, RecordListener { // Déclaration de la commande de sortie private Command cmdExit; // Déclaration de la commande de sauvegarde private Command save; // Déclaration de la commande d'affichage du menu private Command cmdMenu; // Déclaration du gestionnaire d'affichage private Display myDisplay; // Déclaration du composant TextBox qui permettra la saisie de nouveaux enregistrements private TextBox tb = null; // Déclaration de l'enregistrement private Rec rec = null; // Déclaration d'un Record Store private RecordStore myDb = null; // Déclaration d'un composant List qui fera office de menu principal private List menu = null; // Déclaration d'un formulaire pour l'affichage des enregistrements private Form myForm = null; // Déclaration d'un formulaire pour l'affichage du nombre d'enregistrements private Form myFormNb = null; // Déclarations de composants StringItem qui seront associés au formulaire ci-dessus private StringItem strNbRec = null; private StringItem strTailleRec = null; public TestRec () { try { // Ouverture du Record Store (si il n'existe pas, il est créé) myDb = RecordStore.openRecordStore("myDb", true); // Mise en place d'un listener sur le Record Store myDb.addRecordListener(this); } catch (RecordStoreException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible d'ouvrir le Record Store."); myDisplay.setCurrent(errRec); } }

Travail de diplôme - annexe n°2 Roggo Jean-Christophe

- 2 -

// La classe modélisant l'enregistrement public class Rec { private String mot = ""; public Rec(String mot) { this.mot = mot; } // Transforme la chaîne mot en tableau d'octets public byte[] toBytes() { return this.mot.getBytes(); } } // Affichage d'un composant TextBox pour la saisie d'un nouvel enregistrement private void newRec() { tb.setString(""); myDisplay.setCurrent(tb); } // Affichage du menu principal private void mainMenu() { myDisplay.setCurrent(menu); // Pour émettre un son AlertType.CONFIRMATION.playSound(myDisplay); } // Initialise un formulaire private void initForm() { myForm = new Form("Listing"); myForm.addCommand (cmdExit); myForm.addCommand (cmdMenu); myForm.setCommandListener (this); } // Initialisation des différents composants GUI au démarrage de l'application public void startApp() { myDisplay = Display.getDisplay (this); cmdMenu = new Command("Menu", Command.SCREEN, 1); cmdExit = new Command ("Sortie", Command.SCREEN, 2); save = new Command ("Save", Command.OK, 1); tb = new TextBox ("New Rec", "", 1024, 0); tb.addCommand (save); tb.addCommand (cmdExit); tb.addCommand (cmdMenu); tb.setCommandListener (this); this.initForm(); myFormNb = new Form("Nb Rec"); strNbRec = new StringItem("Nombre d'enregistrements : ", ""); strTailleRec = new StringItem("Taille du Record Store : ", ""); myFormNb.append(strNbRec); myFormNb.append(strTailleRec); myFormNb.addCommand (cmdExit); myFormNb.addCommand (cmdMenu); myFormNb.setCommandListener (this); menu = new List("Menu", Choice.IMPLICIT); menu.append("New rec", null); menu.append("Nb rec", null); menu.append("All rec", null); menu.append("Clear all", null); menu.addCommand(cmdExit); menu.setCommandListener(this); // Affichage du menu principal this.mainMenu(); } // Exécuté lorsque l'application est suspendue public void pauseApp() { }

Travail de diplôme - annexe n°2 Roggo Jean-Christophe

- 3 -

// Exécuté lorsque l'application se termine public void destroyApp (boolean unconditional) { try { // Fermeture du Record Store myDb.closeRecordStore(); } catch (RecordStoreException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible de fermer le Record Store."); myDisplay.setCurrent(errRec); } notifyDestroyed(); } // Affiche l'ensemble des enregistrements private void allRec() { int nbRec = 0; String str = ""; try { // Récupération du nombre d'enregistrements contenus dans le Record Store nbRec = myDb.getNumRecords(); } catch (RecordStoreException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible d'accéder au Record Store."); myDisplay.setCurrent(errRec); } // Teste si il y a au moins un enregistrement dans le Record Store if (nbRec > 0) { // Si le formulaire contient moins d'éléments // que le nombre d'enregistrements contenus dans le Record Store, // c'est que la méthode allRec n'a pas encore été exécutée depuis // le lancement de l'application. Le formulaire devra donc être // rénitialisé. En effet, si l'utilisateur a créé des nouveaux // enregistrements avant d'afficher l'ensemble des enregistrements // du Record Store, le listener a répercuté les mises à jour // sur le formulaire. Pour éviter ce test, on aurait pu extraire // les enregistrements du Record Store et les ajouter au formulaire // au démarrage de l'application. Etant donné que l'extraction des // enregistrements est consommatrice de ressources, ce choix // permet un démarrage moins laborieux de l'application. // L'extraction n'est effectuée que si l'utilisateur a besoins // d'afficher l'ensemble des enregistrements. Notons également que // cette extraction n'est effectuée qu'une seule fois pendant la durée // d'exécution de l'application. if (myForm.size() < nbRec){ // Purge du formulaire d’affichage this.initForm() ; byte[] myData = null; try { // On parcours le Record Store for (int i = 1 ; i <= nbRec ; i++ ) { myData = myDb.getRecord(i); if (myData != null){ str = new String(myData); // On ajoute l'enregistrement au formulaire

Travail de diplôme - annexe n°2 Roggo Jean-Christophe

- 4 -

myForm.append(new StringItem("Rec n°" + Integer.toString(i), " : " + str)); } } } catch (RecordStoreException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible d'accéder au Record Store."); myDisplay.setCurrent(errRec); } } // On affiche le formulaire myDisplay.setCurrent(myForm); } else { // Affichage d'une alerte d'information si le Record Store est vide final Alert info = new Alert("Info"); info.setType(AlertType.INFO); info.setString("Le Record Store est vide."); info.setTimeout(Alert.FOREVER); myDisplay.setCurrent(info); } } // Sauve l'enregistrement dans le Record Store private void saveRec() { try { String str = tb.getString(); if (!str.equals("")) {

rec = new Rec(str); myDb.addRecord(rec.toBytes(), 0, rec.toBytes().length); // Affichage d'une alerte indiquant que l'enregistrement a été sauvegardé final Alert info = new Alert ("Info"); info.setType(AlertType.INFO); info.setTimeout(Alert.FOREVER); info.setString("Votre saisie <<" + str + ">> a été enregistrée."); myDisplay.setCurrent(info); tb.setString(""); } } catch (RecordStoreFullException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible d'ajouter l'enregistrement. Le Record Store est plein."); myDisplay.setCurrent(errRec); } catch (RecordStoreException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible d'accéder au Record Store."); myDisplay.setCurrent(errRec); } } // Affiche le nombre d'enregistrements et la taille du Record Store private void countRec() { try {

Travail de diplôme - annexe n°2 Roggo Jean-Christophe

- 5 -

int nbRec = myDb.getNumRecords(); strNbRec.setText(Integer.toString(myDb.getNumRecords())); strTailleRec.setText(Integer.toString(myDb.getSize()) + " octets"); myDisplay.setCurrent(myFormNb); } catch (RecordStoreException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible d'accéder au Record Store."); myDisplay.setCurrent(errRec); } } // Purge du Record Store private void clearAll() { try { // Purge du formulaire d'affichage this.initForm(); // On ferme le Record Store myDb.closeRecordStore(); // On efface le Record Store RecordStore.deleteRecordStore("myDb"); // On affiche une alerte d'information final Alert info = new Alert ("Info"); info.setType(AlertType.INFO); info.setTimeout(Alert.FOREVER); info.setString("Le Record Store est purgé."); myDisplay.setCurrent(info); // On crée un nouveau Record Store de même nom myDb = RecordStore.openRecordStore("myDb", true); // Mise en place du listener sur ce Record Store myDb.addRecordListener(this); } catch (RecordStoreException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible d'accéder au Record Store."); myDisplay.setCurrent(errRec); } } // Gestion des évènements public void commandAction (Command myCommand, Displayable myDisplayable) { if (myCommand == cmdExit) { destroyApp(false); } else if (myCommand == save) { this.saveRec(); } else if (myCommand == cmdMenu) { this.mainMenu(); } else { List list = (List)myDisplay.getCurrent(); switch (list.getSelectedIndex()) {

case 0: this.newRec(); break; case 1:

Travail de diplôme - annexe n°2 Roggo Jean-Christophe

- 6 -

this.countRec(); break; case 2: this.allRec(); break; case 3: this.clearAll(); break; } } }

// Implémentation des méthodes définies dans l'interface Record Listener

// Exécuté lorsqu'un enregistrement est ajouté au Record Store public void recordAdded(RecordStore recordStore, int recordId){ try { // On met le formulaire d'affichage à jour myForm.append(new StringItem("Rec n°" + recordId, " : " + new String(recordStore.getRecord(recordId)))); } catch (RecordStoreException e) { // Affiche une alerte en cas d'erreur final Alert errRec = new Alert ("Erreur"); errRec.setType(AlertType.ERROR); errRec.setString("Impossible d'accéder au Record Store."); myDisplay.setCurrent(errRec); } } // Exécuté lorsqu'un enregistrement du Record Store est modifié. // L'implémentation de cette méthode est vide car l'application n'offre pas la // possibilité de modifier les enregistrements. public void recordChanged(RecordStore recordStore, int recordId){ } // Exécuté lorsqu'un enregistrement du Record Store est supprimé. // L'implémentation de cette méthode est vide car l'application n'offre pas la // possibilité de supprimer les enregistrements un à un. public void recordDeleted(RecordStore recordStore, int recordId){ } }

Vous trouverez ci-dessous quelques illustrations de l’application testRecordStore exécutée sur l’émulateur standard du J2ME Wireless Toolkit 2.1.

Travail de diplôme - annexe n°2 Roggo Jean-Christophe

- 7 -

L’application testRecordStore permet d’enregistrer des chaînes de caractères dans un Record Store (prototype de memo). Lorsque l’application est lancée, le menu principal illustré à la Fig. 2 s’affiche.

En sélectionnant la rubrique New rec, l’écran de saisie d’un nouvel enregistrement de la Fig. 3 s’affiche. En cliquant sur le bouton Menu, les commandes disponibles s’affichent (cf Fig. 4). La commande Menu permet de retourner au menu principal de l’application. La commande Sortie permet de quitter l’application et la commande Save permet de sauvegarder la chaîne de caractères saisie. Lorsque la commande Save est activée l’alerte d’information de la Fig. 9 est affichée pour informer l’utilisateur que sa saisie a été enregistrée dans le Record Store.

En sélectionnant la rubrique Nb rec du menu principal, l’écran illustré à la Fig. 5 s’affiche. Notons que même lorsqu’il est vide, le Record Store occupe un certain espace (stockage d’informations structurelles propres au Record Store).

Fig. 1 Ecran de démarrage de l’application

Fig. 2 Menu principal de l’application

Fig. 3 Ecran de saisie d’un nouvel enregistrement

Fig. 4 Les commandes disponibles depuis l’écran de saisie

Fig. 5 Ecran d’affichage du nombre d’enregistrements

Fig. 6 Ecran d’affichage de l’ensemble des enregistrements

Fig. 7 Alerte affichée lorsque le Record Store est purgé

Fig. 8 Alerte affichée lorsque le Record Store est vide

Fig. 9 Alerte affichée lorsqu’ un enregistrement a été ajouté

Travail de diplôme - annexe n°2 Roggo Jean-Christophe

- 8 -

Lorsque la rubrique All rec du menu principal est sélectionnée, l’écran d’affichage de l’ensemble des enregistrements du Record Store est affiché (cf Fig. 6). Si le Record Store est vide une alerte d’information est affichée (cf Fig. 8).

En sélectionnant la rubrique Clear all du menu principal, le Record Store est effacé puis recréé. Tous les enregistrements sont donc supprimés et une alerte informe l’utilisateur de la purge du Record Store (cf Fig. 7).

Travail de diplôme - annexe n°3 Roggo Jean-Christophe

- 1 -

Annexe n°3 : Mise en œuvre du composant HttpConnection

L’application testHttp est un exemple d’utilisation du composant HttpConnection. Son code source est présenté dans l’encadré ci-dessous.

import java.io.*; import javax.microedition.midlet.*; import javax.microedition.io.*; import javax.microedition.lcdui.*; // MIDlet permettant de télécharger le contenu d'un fichier texte public class TestHttp extends MIDlet { // Déclaration du gestionnaire d'affichage private Display myDisplay; // Déclaration et initialisation d'un chaîne de caractères contenant l'URL // désignant l'emplacement du fichier texte distant private String url = "http://www.ruchat.ch/~yoda/test.txt"; // Déclaration d'un formulaire qui sera utilisé pour afficher // le contenu téléchargé du fichier texte private Form myForm = null; // Constructeur public TestHttp() { myForm = new Form("Résultat"); } // Exécuté au démarrage de l'application public void startApp() { myDisplay = Display.getDisplay(this); try { downloadTxt(url); } catch (SecurityException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); } } // Télécharge le contenu du fichier texte distant private void downloadTxt(String url) throws IOException { StringBuffer b = new StringBuffer(); InputStream is = null; HttpConnection c = null; try { long len = 0 ; int ch = 0; c = (HttpConnection)Connector.open(url); is = c.openInputStream(); len =c.getLength(); if( len != -1) { // Lecture du flux d'octets for(int i =0 ; i < len ; i++ ){ if((ch = is.read()) != -1) { b.append((char) ch); } }

Travail de diplôme - annexe n°3 Roggo Jean-Christophe

- 2 -

} else { // Lecture jusqu'à ce que la connexion soit fermée while ((ch = is.read()) != -1) { len = is.available() ; b.append((char)ch); } } myForm.append(new StringItem("Contenu du fichier texte : ", b.toString())); } finally { if (c != null) { is.close(); c.close(); } } myDisplay.setCurrent(myForm); } // Exécuté lorsque l'application est suspendue public void pauseApp() { } // Exécuté lorsque l'application se termine public void destroyApp(boolean unconditional) { notifyDestroyed(); } }

Vous trouverez ci-dessous quelques illustrations de l’application testHttp exécutée sur l’émulateur standard du J2ME Wireless Toolkit 2.1.

L’application testHttp permet de télécharger le contenu d’un fichier texte via une connexion HTTP. Lorsqu’un MIDlet utilise un composant HttpConnection (ou un autre composant de connexion réseau), le système d’exploitation du terminal mobile affiche l’écran de la Fig. 2 pour des raisons de sécurité. Cet écran demande à l’utilisateur si il autorise l’application à ouvrir une connexion réseau. Si l’utilisateur répond oui, l’application pourra établir des connexions réseaux pendant toute la durée de son

Fig. 1 Ecran de démarrage de l’application

Fig. 2 Ecran de sécurité affiché par le système

Fig. 3 Ecran affichant le résultat du téléchargement

Travail de diplôme - annexe n°3 Roggo Jean-Christophe

- 3 -

exécution. En revanche, si l’utilisateur répond non, l’application ne pourra établir aucune connexion pendant son exécution (l’exception java.lang.SecurityException est déclenchée). Pour pouvoir établir à nouveau une connexion, l’utilisateur devra quitter l’application puis la relancer.

Si l’utilisateur autorise l’application à ouvrir une connexion, l’écran de résultat de la Fig. 3 est affiché une fois le téléchargement terminé.