4D serveur applicatif

Modes de fonctionnement habituels

Les développeurs 4D considèrent habituellement trois modes principaux de fonctionnement d'un moteur 4D :

   1. En application monoposte ;
   2. En architecture client/serveur connectée (c'est-à-dire que toute interruption de la connexion entre client et serveur entraîne une interruption du fonctionnement) ;
   3. En serveur Web : le serveur web de 4D publiant des pages semi-dynamiques HTML à destination d'un navigateur.

On rencontre également des clients 4D utilisés en frontal d'un autre moteur de base de données, par exemple MySQL, au travers d'un plugin natif.

Un autre mode de fonctionnement commence à se faire une place : l'architecture orientée service (SOA) où 4D communique avec d'autres applicatifs au travers de requêtes web service.

Un autre frontal pour 4D

Cas où 4D Client n'est pas une solution

En dehors des pages HTML dans un navigateur, il demeure assez rare de concevoir une architecture 4D où le frontal ne soit pas une application 4D. Cela se justifie par l'excellente intégration du client/serveur 4D et sa grande facilité de déploiement et d'administration.

Cette approche trouve cependant ses limites dans deux cas principaux :

   1. lorsque 4D Client n'est pas disponible pour la plateforme cible : cas des périphériques mobiles qui nous intéresse dans cette note, mais également des machines basées sur Linux ou Unix non OSX ;
   2. lorsque le réseau n'offre pas une qualité suffisante pour permettre au protocole propriétaire de 4D de fonctionner correctement : cas de nombreuses liaisons ADSL.

Fonctionnement en mode semi-connecté

Une architecture permet de répondre à ces cas problématiques : recourir au serveur http de 4D pour transformer 4D en serveur applicatif. Comme dans le cas d'un serveur Web, on utilise le serveur http. Cependant les réponses du serveur ne renvoient plus des pages HTML, mais de l'information destinée à être exploitée par une autre application qui jouera le rôle de frontal. La tendance est aujourd'hui d'utiliser XML pour formater les échanges de données de manière à les rendre universellement exploitables.

Architecture de notre exemple

Voici un schéma illustrant cette approche dans l'exemple présenté dans cette note :

Image non disponible
L'architecture de notre exemple

Séparation des couches

Il est important de noter que, dans cette architecture, l'intégralité de la présentation est assurée par le client Flash. Les messages échangés avec 4D ne comprennent que des données et aucune indication de présentation. En changeant simplement la partie cliente, on peut changer la couche présentation sans retoucher à la couche serveur.

La dissociation des couches est garante d'une bonne maintenabilité et évolutivité de la solution.

Interface virtuelle dans la méthode Sur connexion Web

Deux modes d'invocation de code

Les échanges de requêtes http sont gérés par la couche serveur http de 4D, la même que celle permettant le fonctionnement comme serveur Web. Cependant, les réponses renvoyées ne contiendront pas des pages HTML, mais des données formatées en XML.

Rappelons qu'une requête http peut appeler du code 4D de deux manières différentes :
   · En invoquant directement une méthode par la balise url 4DACTION/ ;
   · En passant par une couche virtuelle d'aiguillage, approche retenue dans notre exemple.

Méthode sur connexion web

Lorsqu'une requête http entrante n'invoque pas directement une ressource existante (page HTML du dossier Web, méthode 4D,…), la méthode base Sur connexion web est appelée et reçoit divers paramètres dont en $1 l'url appelée. Il est alors facile dans une structure « Au cas ou » de traiter la requête entrante en fonction de l'url demandée et d'appeler le code 4D correspondant.

Voici notre code :

code 4D - méthode base Sur connexion web
Sélectionnez

Si (Vrai)  `les paramètres entrants
	C_TEXTE($1;$2;$3;$4;$5;$6)
	C_TEXTE($_vt_URL)
	$_vt_URL:=$1
	
	C_TEXTE($utilisateur;$motPasse;$IPBrowser;$IPServer)
	$utilisateur:=$5
	$motPasse:=$6
	$IPBrowser:=$3
	$IPServer:=$4
Fin de si 

COMPILER_WEB 

Si (http_ve_siDebug=1)
	HTTP_LireCorpsVersPressePapiers 
Fin de si 

C_BOOLEEN($_vb_pocketPc)
$_vb_pocketPc:=HTTP_isPocketPC 

resa_AppelerSurErreur   `installation d'une gestion d'erreurs

Au cas ou 
		  `__________________________________________________________________
	: ($1="/rdv")
		
		Si ($_vb_pocketPc)
			ENVOYER FICHIER HTML("rdv_ppc.html")
		Sinon 
			ENVOYER FICHIER HTML("rdv.html")
		Fin de si 
		  `__________________________________________________________________
	: ($1="/get_Rdvs@")
		resa_getListe ($1)
		  `__________________________________________________________________
	: ($1="/add_Rdv@")
		resa_addRecord ($1)
		  ` _____________________________________________________________
		
	: ($1="/favicon.ico") | ($1="favicon.ico")
		ENVOYER TEXTE HTML("")
		  `__________________________________________________________________
	Sinon 
		HTTP_LireCorpsVersPressePapiers 
		TRACE
Fin de cas


Quelques commentaires :

Une variable http_ve_siDebug permet de basculer dans un mode debug où le contenu de la requête entrante est copié dans le presse-papiers. La variable est typée en entier afin de permettre une extension future, par exemple pour qu'une valeur différente provoque la journalisation des requêtes dans un fichier texte externe ;

La fonction http_isPocketPC analyse les champs d'entête http afin de déterminer si la requête entrante provient d'un PocketPC. Exemple de requête émise par un PocketPC :

  GET/pp HTTP/11
  Accept:*/*
  Accept-Language: fr
  UA-OS: Windows CE(Pocket PC)-Version 4.21
  UA-color: color16
  UA-pixels: 240x240
  UA-CPU: Intel(R)PXA272
  UA-Voice: TRUE
  UA-Language: JavaScript
  Accept-Encoding: gzip, deflate
  User-Agent: Mozilla


Cette fonction exploite le champ UA-OS. Notez que le champ UA-pixels permettrait d'envoyer deux clips Flash différents suivant la résolution de l'écran du périphérique mobile.

En exploitant la fonction http_isPocketPC, il est possible de servir une page différente (et donc un clip Flash différent) suivant que le client soit un PocketPC ou un ordinateur de bureau.

Api de l'exemple

Notre API propose trois entrées matérialisées par des requêtes :

   · /rdv : renvoie une page HTML contenant le clip Flash ;
   · /get/Rdvs/ : renvoie la liste des rendez-vous d'une date donnée, méthode resa_getListe ;
   · /add_Rdv/ : demande l'ajout d'un rendez-vous, méthode resa_addRecord.

Les requêtes inconnues sont ici tracées en mode interprété pour faciliter le déboguage, tandis que les requêtes de navigateurs demandant des favicons (favicon.ico) ne renvoient rien.

Liste des rendez-vous

Méthode resa_getListe

La méthode resa_getListe est appelée par Sur connexion Web.

code 4D - méthode resa_getListe
Sélectionnez

  ` Methode : resa_getListe
  ` Description :
  ` reçoit une date et renvoie la liste des réservations pour cette date
  ` 
  ` Parametres :
  ` $1:TEXTE:URL (/get_Resas/?date=22/5/2006)
  ` 
  ` Version : 1 
  ` Appel : resa_getListe (url) 
  ` ---------------------------------------------------- 
C_TEXTE($1)

C_TEXTE($_vt_faultCode)
$_vt_faultCode:=""
C_TEXTE($_vt_faultString)
$_vt_faultString:=""

C_TEXTE($_vt_param)
$_vt_param:=http_getVar ("Date")

Si ($_vt_param="")  `cas de Flash : passage de param par XML
	  `<getRdv><date>Tue May 30 00:00:00 GMT+0200 2006</date></getRdv>
	C_TEXTE($_vt_refXML)
	$_vt_refXML:=HTTP_DOM_loadXMLfromPOST 
	
	$_vt_param:=DOM_Lire_Valeur_Element_XPath ($_vt_refXML;"/getRdv/Date")
Fin de si 

C_DATE($_vd_dateResa)
$_vd_dateResa:=Date($_vt_param)

Si ($_vd_dateResa#!00/00/00!)
	
	LECTURE SEULEMENT([EVENEMENT])
	CHERCHER([EVENEMENT];[EVENEMENT]Date_evenement=$_vd_dateResa)
	TRIER([EVENEMENT];[EVENEMENT]Heure_evenement;>)
	
	C_BLOB($_vx_blob)
	resa_versXML (->$_vx_blob)
	
	REDUIRE SELECTION([EVENEMENT];0)
	LIBERER ENREGISTREMENT([EVENEMENT])
	
	HTTP_responseByBLOB (->$_vx_blob;"text/xml")
Sinon 
	$_vt_faultCode:="client"
	$_vt_faultString:="Il faut renseigner la date"
	
	HTTP_DOM_sendFault ($_vt_faultCode;$_vt_faultString)
Fin de si

Données entrantes

La requête entrante véhicule la date pour laquelle construire la liste des rendez-vous sous forme d'une structure XML :

<getRdv>
      <date>la date</date>
</getRdv>


La fonction HTTP_DOM_loadXMLfromPOST permet de charger dans un arbre DOM une telle structure XML passée dans les données de la requête, par une méthode POST. Elle retourne la référence de la racine de l'arbre.

code 4D - méthode HTTP_loadXMLfromPOST
Sélectionnez

 ` Methode : HTTP_loadXMLfromPOST
  ` Description :
  ` chargement du XML passé en POST ds un arbre DOM
  ` 
  ` Parametres :
  ` $0:TEXTE:Ref Element cree 
  ` 
  ` Version : 1 
  ` Appel : Ref Element cree :=HTTP_loadXMLfromPOST
  ` ---------------------------------------------------- 

C_TEXTE($0)
$0:=""

C_BLOB($_vx_BLOBXML)
LIRE CORPS HTTP($_vx_BLOBXML)

Si (http_ve_siDebug=1)
	UTF8_vers_ISO_blob (->$_vx_BLOBXML)
	ZBLOB_versPressePapiers (->$_vx_BLOBXML)
Fin de si 

Si (Taille BLOB($_vx_BLOBXML)>0)
	$0:=DOM Analyser variable XML($_vx_BLOBXML)
	Si (ok=0)
		$0:=""
	Fin de si 
Fin de si

Reste à récupérer la valeur recherchée par la fonction DOM_Lire_Valeur_Element_XPath qui retourne la valeur d'un élément désigné par sa notation XPath :

code 4D - méthode DOM_Lire_Valeur_Element_XPath
Sélectionnez

 ` Methode : DOM_Lire_Valeur_Element_XPath
  ` Description :
  ` relire une valeur simple XML par une expression XPath
  ` 
  ` Parametres :
  ` $0:TEXTE:valeur simple XML relue
  ` $1:TEXTE:Ref elt XML de depart
  ` $2:TEXTE:Expression Xpath
  ` 
  ` Version : 1 
  ` Appel : $_vt_personne:=DOM_Lire_Valeur_Element_XPath ($_vt_RefXML;"/root/personne")
  ` ---------------------------------------------------- 

C_TEXTE($1;$_vt_RefXML)
$_vt_RefXML:=$1

C_TEXTE($2;$_vt_XPath)
$_vt_XPath:=$2

C_TEXTE($0)
$0:=""

Si ($_vt_RefXML#"")
	$_vt_RefElement:=DOM Chercher element XML($_vt_RefXML;$_vt_XPath)
	Si (ok=1)
		DOM LIRE VALEUR ELEMENT XML($_vt_RefElement;$0)
	Fin de si 
Fin de si

Ici, l'expression XPath vaut « /getRdv/date », c'est-à-dire l'élément <date> enfant de la racine <getRdv>.

Données sortantes

Si la date est non-vide, nous recherchons les rendez-vous ou événements correspondants, puis nous transformons la sélection correspondante en structure XML afin de la retourner au client Flash.

La méthode resa_versXML créé une structure XML en utilisant les commandes DOM depuis une sélection de [EVENEMENT] et la retourne dans un BLOB.

La méthode HTTP_responseByBLOB renvoie le BLOB passé en paramètre (par pointeur pour économiser la mémoire) dans la réponse http. Le type MIME des données contenues dans le BLOB est passé en deuxième paramètre, il vaut "text/xml" pour une structure XML.

code 4D - méthode HTTP_responseByBLOB
Sélectionnez

 ` Methode : HTTP_responseByBLOB
  ` Description :
  ` envoie la réponse à la requête HTTP
  ` 
  ` Parametres :
  ` $1:POINTEUR:BLOB à envoyer
  ` $2:TEXTE:type MIME, par ex "application/x-shockwave-flash" ou "text/html"
  ` 
  ` Version : 2  
  ` le 24/05/06, 08:32:45 
  `
  ` Appel : HTTP_responseByBLOB (->$_vx_swf;"application/x-shockwave-flash")
  ` ---------------------------------------------------- 
C_POINTEUR($1)  `BLOB
C_TEXTE($2;$_vt_MIME)
$_vt_MIME:=$2

C_ENTIER(http_ve_siDebug)
Si (http_ve_siDebug=1)
	ZBLOB_versPressePapiers ($1)
Fin de si 

ENVOYER BLOB HTML($1->;$_vt_MIME)

Gestion des erreurs

En cas d'erreur, un flux XML est renvoyé par la routine HTTP_DOM_sendFault en respectant la structure suivante :

<response>
      <faultstring>texte de l'erreur<faultstring/>
      vfaultcode>code de l'erreur<faultcode/>
</response>

Ajout d'un rendez-vous

Traitement de la requête

La méthode resa_addRecord est appelée par Sur connexion Web.

code 4D - méthode resa_addRecord
Sélectionnez

  ` ---------------------------------------------------- 
  ` Nom utilisateur (OS) : christophe Keromen 
  ` Date et heure : 27/05/06, 08:06:06
  ` ---------------------------------------------------- 
  ` Methode : resa_addRecord
  ` Description :
  ` ajout d'une réservation depuis le client lz
  ` 
  ` Parametres :
  ` passé par POST
  ` 
  ` Version : 3  
  ` le 21/11/06, 13:06:28 
  ` le 09/06/06, 09:23:37 
  `
  ` Appel : resa_addRecord 
  ` ---------------------------------------------------- 

C_TEXTE($1)

C_TEXTE($_vt_desc)
C_TEXTE($_vt_lib)
C_TEXTE($_vt_hour)
C_TEXTE($_vt_date)
C_TEXTE($_vt_End)

  `requête depuis Flash : data en XML
  `<add_Rdv><date>02/06/2006</date><libelle>Formation Flash</libelle>
  `<heure>9:00</heure><description>Init 3 participants</description></add_Rdv>

C_TEXTE($_vt_refXML)
$_vt_refXML:=HTTP_DOM_loadXMLfromPOST 

Si (ok=1) & ($_vt_refXML#"")
	
	$_vt_date:=DOM_Lire_Valeur_Element_XPath ($_vt_refXML;"/add_Rdv/Date")
	$_vt_lib:=DOM_Lire_Valeur_Element_XPath ($_vt_refXML;"/add_Rdv/libelle")
	$_vt_hour:=DOM_Lire_Valeur_Element_XPath ($_vt_refXML;"/add_Rdv/Heure")
	$_vt_desc:=DOM_Lire_Valeur_Element_XPath ($_vt_refXML;"/add_Rdv/description")
	
	C_DATE($_vd_date)
	$_vd_date:=Date($_vt_date)
	
	C_HEURE($_vh_heure)
	$_vh_heure:=Heure($_vt_hour)
	
	C_HEURE($_vh_heureFin)
	$_vh_heureFin:=Heure($_vt_End)
	
	C_TEXTE($_vt_faultCode)
	$_vt_faultCode:=""
	C_TEXTE($_vt_faultString)
	$_vt_faultString:=""
	
	Si ($_vd_date#!00/00/00!) & ($_vh_heure#?00:00:00?)
		
		C_ENTIER LONG($_vl_ts)
		$_vl_ts:=zgen_getTimeStamp ($_vd_date;$_vh_heure)
		
		C_ENTIER LONG($_vl_count)
		FIXER DESTINATION RECHERCHE(Vers variable ;$_vl_count)
		CHERCHER([EVENEMENT];[EVENEMENT]Jour_TS=$_vl_ts)
		FIXER DESTINATION RECHERCHE(Vers sélection courante )
		
		Si ($_vl_count=0)
			
			CREER ENREGISTREMENT([EVENEMENT])
			[EVENEMENT]Date_evenement:=$_vd_date
			[EVENEMENT]Description:=$_vt_desc
			[EVENEMENT]Heure_evenement:=$_vh_heure
			[EVENEMENT]Fin_evenement:=$_vh_heureFin
			[EVENEMENT]Libelle:=$_vt_lib
			STOCKER ENREGISTREMENT([EVENEMENT])
			LIBERER ENREGISTREMENT([EVENEMENT])
			
			Si (resa_vt_error#"")  `erreur ds le trigger par ex.
				$_vt_faultCode:="server"
				$_vt_faultString:=resa_vt_error
			Fin de si 
			
		Sinon 
			$_vt_faultCode:="client"
			$_vt_faultString:="Il existe déjà un événement à cette date et cette heure"
		Fin de si 
	Sinon 
		$_vt_faultCode:="client"
		$_vt_faultString:="Il faut renseigner date et heure"
	Fin de si 
	
Sinon 
	$_vt_faultCode:="client"
	$_vt_faultString:="Les paramètres passés ne sont pas corrects"
Fin de si 

C_TEXTE($_vt_ref_XML)
$_vt_ref_XML:=HTTP_DOM_creer_ref_XML ("response")

Si ($_vt_faultCode="")
	DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_ref_XML;"result";"true")  `true
	  `<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><response><result>true</result></response>
Sinon 
	HTTP_DOM_AddFault ($_vt_ref_XML;$_vt_faultString;$_vt_faultCode)
Fin de si 

HTTP_DOM_envoyer_XML ($_vt_ref_XML)

Le principe est le même que pour la méthode précédente.

Gestion des erreurs

Exemple d'implémentation de règle de gestion en trigger, la méthode resa_trigger est appelée dans le trigger de la table [EVENEMENT] :

code 4D - méthode resa_trigger
Sélectionnez

C_ENTIER LONG($_vl_event)
$_vl_event:=Evenement moteur

C_ENTIER LONG($0)
$0:=resa_trigger ($_vl_event)

 ` Elle remonte une erreur si l'on tente d'enregistrer un événement en dehors des plages autorisées :

 ` Methode : resa_trigger
  ` Description :
  ` traitement en trigger de la table [RESERVATION]
  ` 
  ` Parametres :
  ` $0:ENTIER LONG:erreur
  ` $1:ENTIER LONG:evenement moteur 
  ` 
  ` Version : 1 
  ` Appel : erreur:=resa_trigger(evenement moteur ) 
  ` ---------------------------------------------------- 

C_ENTIER LONG($1;$_vl_event)
$_vl_event:=$1

C_ENTIER LONG($0)
$0:=0

Au cas ou 
	: ($_vl_event=Sur sauvegarde enregistrement ) | ($_vl_event=Sur sauvegarde nouvel enreg )
		
		[EVENEMENT]Jour_TS:=zgen_getTimeStamp([EVENEMENT]Date_evenement;
                    [EVENEMENT]Heure_evenement)
		
		Si ([EVENEMENT]PK_evenement=0)
			[EVENEMENT]PK_evenement:=Numerotation automatique([EVENEMENT])
		Fin de si 
		
		  `ex. de regle de gestion
		Si ([EVENEMENT]Heure_evenement<?07:00:00?) | ([EVENEMENT]Heure_evenement>?21:00:00?)
			$0:=-32000
		Fin de si 
		
Fin de cas

L'erreur remontée dans le trigger est capturée par le gestionnaire d'événement resa_handle_error, installé par resa_AppelerSurErreur dans la méthode Sur Connexion Web. Le gestionnaire positionne un code et un message d'erreur :

code 4D - méthode resa_handleError
Sélectionnez

 ` Methode : resa_handleError
  ` Description :
  ` Gestionnaire d'erreurs des réservations
  ` 
  ` Parametres :
  ` 
  ` 
  ` Version : 1 
  ` Appel : resa_handleError
  ` ---------------------------------------------------- 

C_ENTIER LONG(resa_vl_error)
resa_vl_error:=error

Au cas ou 
	: (resa_vl_error=-32000)
		resa_vt_error:="L'heure de réservation doit être comprise entre 07h et 21h"
		
	Sinon 
		resa_vt_error:="Erreur inconnue "+Chaine(resa_vl_error)
Fin de cas

Si une erreur est détectée, la réponse http renvoie un faultCode et une faultString en respectant la structure décrite précédemment.

Comparaison avec SOAP

Structure propriétaire

Les échanges de message sont très semblables à des échanges SOAP. Cependant, la structure des messages est propriétaire, on n'y trouve pas d'enveloppe SOAP contenant un BODY contenant le message. Le client doit donc connaître la structure propriétaire pour fonctionner : pas d'interopérabilité. Pas non plus de description par un fichier WSDL à la structure formalisée. Il vous revient de documenter l'API de votre serveur applicatif.

Meilleure prise en compte des structures XML

En revanche, travaillant au plus près des échanges, le développeur maîtrise mieux le contenu de ceux-ci. En particulier, devenant responsable du codage et décodage des informations en XML, il peut éviter certains aspects automatiques de la couche SOAP de 4D non adaptés aux structures XML complexes :

   · Encodage base64 superflu ;
   · Traitement des structures XML comme du texte et application des règles de syntaxe XML, par exemple transformation des <> en entités.

Vitesse accrue

La couche SOAP entraîne une consommation de ressources supplémentaires qu'il est précieux de pouvoir économiser sur un périphérique de faible puissance CPU comme le PocketPC.

Côté client Flash

Nous n'allons pas ici entamer une formation à Flash. Nous nous contenterons de rappeler les principes de développement côté Flash.

Composants

Image non disponible
L'interface de l'IDE Flash


La réalisation d'interface dans Flash s'appuie sur l'utilisation de composants.

Interface

On voit sur la droite (palette Components) un extrait de la liste des composants d'interface (User Interface) proposés par Flash.

Dans notre exemple, sont utilisés les composants d'interface suivants :

   · TextInput : saisie de la date
   · DataGrid : liste des rendez-vous
   · TextField : affichage de texte dynamique

Données

Ces composants reçoivent leurs données de composants dédiés, présents dans notre copie d'écran sur fond gris :

   · Un composant XMLconnector se charge des échanges http véhiculant de l'XML ;
   · Un composant DataSet joue le rôle de conteneur des données relues depuis la source XMLconnector.

Liaisons

Des liaisons peuvent être établies par l'inspecteur de composants (palette Component Inspector en bas à droite de notre copie d'écran).

On voit dans notre exemple que l'instance du composant d'interface DataGrid nommée rdvListe_dg est liée (bound to) au composant de donnée rdvListe_ds, instance du composant DataSet, par la propriété dataProvider (fournisseur de données).

Ces liaisons sont mises en œuvre automatiquement par Flash dès qu'un événement de mise à jour est détecté.

De son côté le composant DataSet est lié au composant XMLConnector. Ainsi, lorsqu'une requête http est traitée par le composant XMLConnector, celui-ci notifie le composant DataSet qui reçoit les données et les fait suivre, après d'éventuelles transformations, aux composants d'interface abonnés. Ici la dataGrid. Le même mécanisme est mis en jeu entre la dataGrid et le composant TextField qui affiche la description d'un rendez-vous dès qu'une ligne est sélectionnée dans la liste.

Programmation

Séparation du comportement

Quoique ce mécanisme de liaisons apporte un automatisme de mise en œuvre important, il demeure cependant nécessaire d'écrire du code. Une bonne pratique de programmation consiste à ne pas l'inclure dans l'équivalent des méthodes objets des éléments d'interface, mais à définir une classe de gestion du formulaire qui assurera la prise en compte du comportement.

ActionScript

Ces classes sont écrites en ActionScript, le langage propriétaire de Flash, une mouture du langage ECMAScript, standard dont est issu également JavaScript :
http://fr.wikipedia.org/wiki/ECMAScript

Ainsi, pour un développeur maîtrisant la syntaxe JavaScript, le passage vers ActionScript ne posera pas de difficulté.

Chaque classe est enregistrée dans un fichier texte dédié suffixé par .as.

Edition du code ActionScript

Le code ActionScript peut ainsi être édité dans des outils indépendants de l'IDE fourni par Adobe. J'utilise l'excellent SE|PY écrit en Python, bien plus pratique que l'éditeur natif de Flash :

Image non disponible
Exemple d'édition de code ActionScript dans SE|PY



Site web de SE|PY : http://www.sephiroth.it/python/sepy.php

Pour plus d'informations sur Flash et le PocketPC :
http://www.adobe.com/devnet/devices/pocket_pc.html

Conclusion

Nous avons détaillé dans cette note la réalisation d'une interface applicative http-XML dans 4D, pouvant être considérée comme une alternative propriétaire à SOAP. Nous avons également présenté les concepts de réalisation de la partie cliente dans Adobe Flash.

La combinaison des deux outils, sans égaler la simplicité et la rapidité de réalisation d‘une solution purement 4D, permet néanmoins de répondre à des cas de figure complémentaires :

   · Réseau lent ou mode semi-connecté (ADSL, GPRS, Edge) ;
   · OS non supporté par 4D : Linux ;
   · Périphériques non supportés par 4D : PocketPC, smartphones…

Télécharger la base exemple


Télécharger la base exemple.