Ada et Internet Ada and the Internet Conférence Ada-France dans le cadre du workshop "Methods and Tools for Ada 95" (Brest, 16 Septembre 1999) J-P. Rosen: "Ada pour développer sur Internet" S. Moody: "Ada and the Internet: Information Linking, Agents and the scale of the Web" T. Quinot: " CIAO: Opening the Ada 95 Distributed Systems Annex to CORBA Clients" E. Briot: "JGNAT: The GNAT Ada 95 environment for the environment for the JVM" Ada pour développer sur Internet Jean-Pierre Rosen Adalog 27, avenue de Verdun 92170 VANVES FRANCE Résumé Ada permet de réaliser des applications liées à l’Internet aussi bien que n’importe quel langage. Mais le terme "application Internet" englobe des besoins différents. On distingue les services de pages Web dynamiques côté serveur (interface CGI), les animations de page côté client (Java), et l’écriture d’application autonomes utilisant Internet. Pour chacune de ces possibilités, des outils sont disponibles facilitant l’écriture d’applications en Ada. 1 Introduction On peut bien entendu réaliser en Ada tout ce qui peut se faire dans d’autres langages. Mais en pratique, cela peut être plus ou moins facile selon les bibliothèques dont on dispose. Dans ce papier, nous présentons rapidement les différentes facettes de la programmation Internet, et faisons un panorama des services permettant de développer des applications liées à Internet en Ada, aussi bien en tant que client qu’en tant que serveur. 2 L’interface CGI L’interface CGI [1] (Common Gateway Interface, à ne pas confondre avec la norme graphique Computer Graphic Interface) permet de créer des pages Web dynamiques, c’est à dire dont le contenu est fourni par l’exécution d’un programme et non sous la forme d’un fichier figé. 2.1 Principe de fonctionnement du CGI Lorsqu’un serveur HTTP se voit demander une URL désignant un fichier figurant sous un répertoire spécial (souvent appelé CGI-BIN), il le considère comme un exécutable, le lance, et renvoie le produit de sa sortie standard (le STANDARD_OUTPUT de Ada) au client. C’est aussi simple que cela. Enfin presque... Tout d’abord, le serveur doit connaître le type des données renvoyées par le programme. Pour cela, E-m: [email protected] URL: http://pro.wanadoo.fr/adalog le texte doit commencer par une ou plusieurs lignes fournissant des indications sur le contenu de ce qui suit. Ces lignes d’en-tête sont séparées du contenu proprement dit par une ligne vide. Cela peut être, par exemple : Content-type: text/html pour indiquer du HTML normal, ou : Location: http://monserveur.fr/reponse pour indiquer que la réponse se trouve dans un autre fichier. Ensuite, il est bien évident que les pages dynamiques n’ont d’intérêt que si elles permettent de répondre à une demande particulière du client ; il faut donc que le client passe des données à l’application... et que celle-ci soit capable de les récupérer. Côté client, cela se fait en mettant dans l’URL, derrière le nom du fichier, des indications de la forme Clé=Valeur, séparées par des points d’interrogation. Dans les valeurs, tous les espaces sont remplacés par des caractères "+", et tous les caractères non alphanumériques sont représentés par leur valeur hexadécimale sous la forme "%xx". Noter que rien n’est imposé quant à la façon dont ces paramètres sont mis par le client dans l’URL : il est parfaitement possible de les mettre directement dans une référence (balise HREF), mais en général ils proviendront d’un formulaire. Dans ce cas, le descriptif du formulaire contient l’URL du fichier CGI à activer, et c’est le logiciel client qui rajoute les noms et les valeurs des différents champs du formulaire derrière le nom du fichier. Il existe plusieurs façons de récupérer ces valeurs côté serveur, mais nous ne présenterons ici que la plus habituelle. Avant de lancer l’application CGI, le serveur HTTP initialise des variables d’environnement avec diverses informations. La plus intéressante est QUERY_STRING, qui contient la chaîne de caractère suivant le premier "?" dans l’URL, c’est-à-dire tout l’ensemble des paramètres. Le logiciel n’a donc qu’à récupérer le contenu de cette variable, la décoder, et produire ce qu’il veut en sortie. Remarquer qu’avec l’interface CGI, l’application est lancée sur le serveur, ce qui pourrait poser des problèmes de sécurité. C’est pour cette raison que seuls les exécutables "autorisés" (ceux du répertoire spécialement marqué dans le serveur) peuvent être lancés de cette façon. En revanche, il n’y a aucune restriction au type d’exécutable : ce peutêtre des programmes développés dans un langage conventionnel, ou des scripts en Shell, PERL, Tcl... 2.2 L’interface Ada-CGI Il existe un paquetage [2] pour faciliter l’écriture d’applications CGI en Ada. Ce paquetage a été écrit par David Wheeler, qui en autorise l’utilisation sans aucune restriction1 du moment que l’on n’oublie pas de mentionner que c’est lui qui l’a écrit... ce qui est fait maintenant. A priori, la seule chose réellement nécessaire pour écrire un programme CGI est la faculté de récupérer la valeur d’une variable d’environnement. En pratique, il faut analyser la chaîne pour séparer les différentes paires Clé=Valeur et décoder les espaces et les encodages hexadécimaux. Ce sont ces services qui sont fournis par le paquetage CGI, ainsi que des utilitaires facilitant la production de l’HTML en sortie. valeurs de tous les paramètres (pour la mise au point), et la fonction Get_Environment permet de récupérer la valeur de n’importe quelle variable d’environnement. Une dernière remarque : si ce paquetage ne représente pas une quantité de travail énorme, il est bien utile en affranchissant le programmeur de toute la partie fastidieuse du décodage des paramètres. De plus, c’est un bon exemple d’utilisation des nouvelles fonctionnalités Ada 95 de manipulations de chaînes de caractères. 2.3 UnCGI Une autre façon de simplifier le décodage des paramètres CGI est d’utiliser UnCGI [3]. Ce programme agit comme un pré-processeur qui décode les associations Clés/Valeurs, crée des variables d’environnement portant le nom des clés, puis appelle un programme utilisateur... qui peut être écrit en Ada, comme dans n’importe quel autre langage. La spécification complète du paquetage est donnée en annexe 1. Noter que tous les sous-programmes produisant des chaînes de caractères sont doublés pour retourner soit des String, soit des Unbounded_String. Les principales fonctionnalités fournies sont : Pour être honnête, cette interface est surtout utile avec les langages de script, pour lesquels il est plus simple d’accéder aux variables d’environnement que de faire des entrées/sorties. 1) La gestion des paramètres. Les différentes fonctions Value permettent de récupérer la valeur associée à une clé (le paramètre Index désignant l’occurrence de la clé voulue, celle-ci pouvant apparaître plusieurs fois). Les fonctions Key_Exists pemettent de savoir si une clé est présente, et Key_Count le nombre d’occurrences. Il est également possible (fonctions Key et Value) de connaître la clé (et la valeur associée) se trouvant à une position donnée dans la liste. Le nombre total de paramètres est fourni par la fonction Argument_Count. 2) La production d’HTML. La procédure Put_CGI_Header permet de fournir la première ligne d’en-tête. Les procédures Put_HTML_Head et Put_HTML_Tail impriment les début/fin standard de document HTML. La procédure Put_HTML_Head sort un texte sous forme de titre standard (balises Hn, avec n=1 par défaut). Enfin la procédure Put_Error_Message génère une page complète contenant un message d’erreur. 3) La gestion des lignes. Une valeur de paramètre peut s’étendre sur plusieurs lignes. La fonction Line_Count donne le nombre de lignes dans une valeur, et la fonction Line_Count_Of_Value donne le nombre de lignes d’une valeur associée à une clé. De même, les fonctions Line et Line_Of_Value permettent de récupérer la nième ligne d’une chaîne, ou d’une valeur associée à une clé. 4) Des fonctions de plus bas niveau. La procédure Put_Variables imprime (sous forme HTML) les 3 Les applets Java 1 En particulier, sans les restrictions de la licence GPL. Contrairement au CGI, les applets permettent d’exécuter des programmes sur l’ordinateur du client, c’est à dire sur la machine qui demande l’affichage de la page Web. C’est surtout utile pour faire des animations, ou des interfaces plus sophistiquées que ce qu’autorise l’HTML standard. Le fournisseur d’une page HTML ignorant tout de la machine qui l’affiche, il fallait définir pour les applets un format exécutable indépendant de toute architecture matérielle. Java définit donc une machine virtuelle, exécutant un code machine appelé Byte-code. Une applet n’est donc physiquement qu’une référence à un fichier contenant du byte-code. Lors du chargement de la page, ce code est transmis à un interpréteur (interne au browser) qui l’exécutera. L’interpréteur aura la charge de contrôler le code téléchargé, et en particulier de limiter ou d’interdire des fonctionnalités qui pourraient être dangereuses pour la machine sur laquelle il s’exécute, comme d’effacer ou modifier des fichiers locaux ! Noter que la machine virtuelle Java est multi-tâche, ce qui est très utile pour réaliser des animations. Toutefois, les fonctionnalités de synchronisation et de communication offertes restent très élémentaires, comparées aux possibilités d’Ada. Sun, qui est à l’origine de Java, a développé un langage spécifique, le langage Java, et fournit un compilateur traduisant ce langage en byte-code. Ce compilateur fait partie d’un ensemble de composants, le JDK (Java Development Kit), qui est téléchargeable gratuitement [4]. Le langage Java est purement orienté objet, c’est-à- dire que tout est défini sous forme de classes, et que, à part quelques types (très) élémentaires, toutes les entités manipulées sont à sémantique de référence. Cet aspect est particulièrement déroutant pour les développeurs habitués à des langages conventionnels, et conduit à d’importantes inefficacités, notamment dans les manipulations de tableaux. Un des intérêts de Java est le grand nombre de classes fournies avec l’environnement, qui permettent de développer des interfaces sophistiquées, de jouer de la musique, d’établir des liaisons internet, etc. On notera cependant que les classes de base résident sur la machine hôte ; comme les fonctionnalités ont été rajoutées progressivement dans les différentes versions de l’environnement, les plus récentes d’entre-elles (et souvent les plus intéressantes) risquent de ne pas fonctionner avec les browsers les plus anciens, ce qui impose de se limiter si l’on veut que les applets fonctionnent partout. 3.1 Principe de fonctionnement des applets Java Une applet devant fonctionner dans une page HTML est un objet appartenant à une classe dérivée de la classe Applet. Cette classe fournit un certain nombre de méthodes, dont certaines devront être en général redéfinies. On trouve ainsi Paint, qui est chargée de redessiner le contenu de l’applet, méthode appelée par le browser à chaque fois qu’il est nécessaire de remettre à jour l’écran ; init, qui permet d’initialiser l’applet, appelée par le browser la première fois que la page est chargée ; start et stop, appelées par le browser respectivement lorsque la page devient visible ou est cachée, ce qui évite de laisser "courir" des animations lorsqu’elles ne sont pas visibles ; enfin destroy, qui doit libérer les ressources utilisées, qui est appelée par le browser lorsque la page disparaît définitivement. JGNAT n’ayant pas encore été diffusé à la date d’écriture de ces lignes, nous donnerons juste quelques indications concernant la technologie Intermetrics. Une classe Java correspond à un paquetage Ada contenant la déclaration d’un type étiqueté dont le nom doit obligatoirement être celui du paquetage auquel on ajoute "_Obj". A part cela, il s’utilise comme n’importe que type étiqueté. Attention toutefois à un piège : Java dépendant des majuscules/minuscules, il faut que le nom du paquetage donné en tête de spécification respecte exactement la mise en majuscule de la classe Java. Toutes les classes Java ont été interfacées et sont disponibles depuis Ada. Il existe également un paquetage Interfaces.Java qui assure la compatibilité des types de données et facilite la correspondance entre chaînes de caractères Java et Ada. Grâce à cela, il n’est pas plus difficile d’utiliser les classes Java que n’importe quelle autre bibliothèque pour laquelle un binding Ada a été défini. Noter également que le compilateur produit des classes compilées absolument standard, et qu’il est donc possible d’utiliser des classes écrites en Ada depuis n’importe quel programme écrit en langage Java. 3.3 Exemple d’Adapplet A titre d’exemple, nous fournissons en annexe 2 une petite applet en Ada qui affiche un menu déroulant contenant des pages web à choisir, et un bouton pour provoquer l’affichage de la page désirée. Une fois intégrée dans une page HTML, l’effet produit est le suivant : 3.2 Ecriture d’applets Java en Ada A priori, rien n’impose un langage particulier pour produire le byte-code ; il existe un grand nombre de compilateurs pour des langages variés (118 selon [5]) qui génèrent du byte-code au lieu de code natif, y-compris plusieurs assembleurs. Cela ne présente pas de difficulté théorique, il ne s’agit en fait que de compilateurs croisés ayant la machine virtuelle Java pour cible. En particulier, il est possible de générer du byte-code, et donc d’écrire des applets, à partir d’Ada1. Cela a été réalisé par la technologie AppletMagic d’Intermetrics [7] (aujourd’hui Averstar), que l’on retrouve dans les compilateurs basés sur ce frontal, notamment le compilateur Aonix [8]. Plus récemment, une version spéciale du compilateur GNAT (nommée JGNAT) a été développée pour la machine Java par ACT [9]. 1 Nous proposons d’appeler les applets écrites en Ada des "Adapplets". Voir la page qui leur est consacrée sur le site Adalog [6]. Dans cette applet, on a juste redéfini la méthode Init qui met en place les éléments (menu déroulant, bouton) et la méthode action qui définit les traitements à effectuer en cas d’évènement concernant l’applet. Remarquer la présence d’un opérateur unaire "+" qui transforme les chaînes Ada en chaînes Java. Des exemples d’Adapplets librement réutilisables (y compris une version plus évoluée de celle-ci) sont disponibles depuis la page des composants Adalog [10]. 4 L’accès à Internet depuis Ada Le dernier volet des applications possibles de Ada dans le monde de l’Internet concerne le développement d’applications utilisant Internet, telles que des logiciels de courrier électronique, des browsers, des transferts de fichiers, etc. La problématique particulière à Internet, pour de telles applications, se trouve évidemment dans l’interfaçage avec le réseau. 4.1 Les ANC (Ada Network Components) Il s’agit d’un ensemble de paquetages développés à l’ENST qui fournissent une interface avec les sockets qui constituent l’inteface système normale avec le réseau. Ces composants sont sous licence GPL "assouplie" (modèle de la bibliothèque GNAT), et sont disponibles depuis [11]. Cette interface peut être qualifiée de "moyenne" (ni mince, ni épaisse) dans la mesure où le typage a été adapté à Ada, mais où les fonctionnalités fournies correspondent exactement à l’interface socket du système. Nous donnons à titre d’exemple, en annexe 3, la spécification du paquetage Sockets. 4.2 AdaJNI Le JNI (Java Native Interface) est une interface permettant d’exécuter du code Java depuis un programme en C (ainsi, d’ailleurs, qu’inversement). Cela revient, en gros, à incorporer dans le programme une machine virtuelle, et à lui faire exécuter le code des classes Java que l’on souhaite utiliser. La société Ainslie-Software [12] vend une interface appelée AdaJNI qui fournit les mêmes services à des programmes Ada. Il devient ainsi possible d’utiliser tous les services de la riche bibliothèque Java depuis un programme Ada natif. En particulier, la bibliothèque Java comporte de nombreuses classes d’interface avec le réseau, ce qui en fait une alternative intéressante pour l’écriture d’applications Internet portables. gnements à ce sujet peuvent être obtenus depuis l’excellent site AdaPower [15], ou la fameuse "page Ada" de Pascal Obry [16]. Et n’oubliez pas que si vous avez eu un besoin qui vous a conduit à créer une nouvelle interface avec une bibliothèque existante, d’autres pourraient bien avoir le même besoin... Pensez à mettre votre travail à disposition sur Internet ; de nombreux sites sont prêts à héberger le fruit de vos efforts ! 6 Conclusion Les mêmes outils sont aujourd’hui disponibles pour développer des applications Internet avec Ada qu’avec les autres langages. On doit cet (heureux) état de fait aux nouvelles facilités d’interfaçage apportées par Ada 95, et au développement de l’Internet lui-même, qui permet de mettre le travail de chacun à disposition de tous. Même pour ce type d’application, où le C est traditionnellement utilisé, l’alternative est disponible ; le choix du langage doit donc être guidé par les critères habituels de génie logiciel, maintenance, etc. Encore faut-il savoir, et faire savoir, que le choix existe ! Webliographie [1] CGI : http://hoohoo.ncsa.uiuc.edu/cgi [2] Ada-CGI : http://goanna.cs.mit.edu.au/~dale/cgi/cgi.htm [3] UnCGI : http://www.midwinter.com/~koreth/uncgi.html [4] JDK : http://java.sun.com/products/jdk/1.2/ [5] Langages pour la Java machine : http://grunge.cs.tu-berlin.de/~tolk/vmlanguages.html Il existe également une version "libre" de l’interface Ada-JNI, appelée Café1815 [13], mais elle est actuellement en version Alpha. A suivre... [6] Adapplets: http://pro.wanadoo.fr/adalog/adapple1.htm 5 Et si cela ne suffit pas... [9] ACT :http://www.act-europe.fr Si malgré tout les outils précédants ne répondent pas à vos besoins, rappelons qu’il est possible d’utiliser en Ada n’importe quelle bibliothèque interfacée avec le langage C. L’adaptation d’une bibliothèque C peut être grandement facilitée par l’utilisation de l’outil C2ADA [14] qui traduit (presque) automatiquement un fichier d’en-tête C (".h") en spécification Ada. Il est également possible d’utiliser des services fournis sous forme de DLL ou d’utiliser l’interface COM de Microsoft ; tous les rensei- [7] AppletMagic : http://www.appletmagic.com [8] Aonix : http://www.aonix.fr [10] Composants Adalog : http://pro.wanadoo.fr/adalog/ compo1.htm [11] Ada Network Components : http://www.inf.enst.fr/ANC [12] Ainslie Software : http://www.ainslie-software.com [13] Café 1815 : http://www.acenet.com.au/~gbull/ [14] C2ADA : http://www.inmet.com/~mg/c2ada/c2ada.html [15] AdaPower : http://www.AdaPower.com [16] Pascal Obry : http://ourworld.compuserve.com/homepages/pascal_obry/ada.html Annexe 1 : spécification du paquetage CGI with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; package CGI is -- This package is an Ada 95 interface to the "Common Gateway Interface" (CGI). -- This package makes it easier to create Ada programs that can be -- invoked by World-Wide-Web HTTP servers using the standard CGI interface. -- CGI is rarely referred to by its full name, so the package name is short. -- General information on CGI is available at "http://hoohoo.ncsa.uiuc.edu/cgi/". -- Developed by (C) David A. Wheeler ([email protected]) June 1995. -- This is version 1.0. ------- This was inspired by a perl binding by Steven E. Brenner at "http://www.bio.cam.ac.uk/web/form.html" and another perl binding by L. Stein at "http://www-genome.wi.mit.edu/ftp/pub/software/WWW/cgi_docs.html" A different method for interfacing binding Ada with CGI is to use the "Un-CGI" interface at "http://www.hyperion.com/~koreth/uncgi.html". ------ This package automatically loads information from CGI on program start-up. It loads information sent from "Get" or "Post" methods and automatically splits the data into a set of variables that can be accessed by position or by name. An "Isindex" request is translated into a request with a single key named "isindex" with its Value as the query value. ------- This package provides two data access methods: 1) As an associative array; simply provide the key name and the value associated with that key will be returned. 2) As a sequence of key-value pairs, indexed from 1 to Argument_Count. This is similar to Ada library Ada.Command_Line. The main access routines support both String and Unbounded_String. -- See the documentation file for more information and sample programs. function Parsing_Errors return Boolean; function Input_Received return Boolean; function Is_Index return Boolean; -- An "Isindex" request is turned into -- with Value(1) as the actual query. -- True if Error on Parse. -- True if Input Received. -- True if an Isindex request made. a Key of "isindex" at position 1, type CGI_Method_Type is (Get, Post, Unknown); function CGI_Method return CGI_Method_Type; -- True if Get_Method used. -- Access data as an associative array - given a key, return its value. -- The Key value is case-sensitive. -- If a key is required but not present, raise Constraint_Error; -- otherwise a missing key's value is considered to be "". -- These routines find the Index'th value of that key (normally the first one). function Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String; function Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return String; function Value(Key : in Unbounded_String; Index : in Positive := 1; Required : in Boolean := False) return String; function Value(Key : in String; Index : in Positive := 1; Required : in Boolean := False) return Unbounded_String; -- Was a given key provided? function Key_Exists(Key : in String; Index : in Positive := 1) return Boolean; function Key_Exists(Key : in Unbounded_String; Index : in Positive := 1) return Boolean; -- How many of a given key were provided? function Key_Count(Key : in String) return Natural; function Key_Count(Key : in Unbounded_String) return Natural; -- Access data as an ordered list (it was sent as Key=Value); -- Keys and Values may be retrieved from Position (1 .. Argument_Count). -- Constraint_Error will be raised if (Position < 1 or Position > Argument_Count) function Argument_Count return Natural; -- 0 means no data sent. function Key(Position : in Positive) return Unbounded_String; function Key(Position : in Positive) return String; function Value(Position : in Positive) return Unbounded_String; function Value(Position : in Positive) return String; -- The following are helpful subprograms to simplify use of CGI. function My_URL return String; -- Returns the URL of this script. procedure Put_CGI_Header(Header : in String := "Content-type: text/html"); -- Put CGI Header to Current_Output, followed by two carriage returns. -- This header determines what the program's reply type is. -- Default is to return a generated HTML document. procedure Put_HTML_Head(Title : in String; Mail_To : in String := ""); -- Puts to Current_Output an HTML header with title "Title". This is: -<HTML><HEAD><TITLE> _Title_ </TITLE> -<LINK REV="made" HREF="mailto: _Mail_To_ "> -</HEAD><BODY> -- If Mail_To is omitted, the "made" reverse link is omitted. procedure Put_HTML_Heading(Title : in String; Level : in Positive); -- Put an HTML heading at the given level with the given text. -- If level=1, this puts: <H1>Title</H1>. procedure Put_HTML_Tail; -- This is called at the end of an HTML document. It puts to Current_Output: -</BODY></HTML> procedure Put_Error_Message(Message : in String); -- Put to Current_Output an error message. -- This Puts an HTML_Head, an HTML_Heading, and an HTML_Tail. -- Call "Put_CGI_Header" before calling this. procedure Put_Variables; -- Put to Current_Output all of the CGI variables as an HTML-formatted String. function Line_Count (Value : in String) return Natural; -- Given a value that may have multiple lines, count the lines. -- Returns 0 if Value is the empty/null string (i.e., length=0) function Line_Count_of_Value (Key : String) return Natural; -- Given a Key which has a Value that may have multiple lines, -- count the lines. Returns 0 if Key's Value is the empty/null -- string (i.e., length=0) or if there's no such Key. -- This is the same as Line_Count(Value(Key)). function Line (Value : in String; Position : in Positive) return String; -- Given a value that may have multiple lines, return the given line. -- If there's no such line, raise Constraint_Error. function Value_of_Line (Key : String; Position : Positive) return String; -- Given a Key which has a Value that may have multiple lines, -- return the given line. If there's no such line, raise Constraint_Error. -- If there's no such Key, return the null string. -- This is the same as Line(Value(Key), Position). function Get_Environment(Variable : in String) return String; -- Return the given environment variable's value. -- Returns "" if the variable does not exist. end CGI; Annexe 2 : Exemple d’applet Java en Ada -------------------------------------------------------------------------------- Adapplet filesel --- (C) Copyright 1998 ADALOG -------------------------------------------------------------------------------with Java.Lang, Java.Applet.Applet, Java.Awt.Event; use Java.Lang, Java.Applet.Applet; -- Clauses for private part only: with Java.Awt.Button, Java.Awt.Choice; package filesel is type Filesel_Obj is new Applet_Obj with private; procedure init (Obj function action (Obj Evt What return Boolean; : : : : access Filesel_Obj); access Filesel_Obj; Java.Awt.Event.Event_Ptr; Object_Ptr) private use Java.Awt.Button, Java.Awt.Choice; type Filesel_Obj is new Applet_Obj with record Download_Button : Button_Ptr; Format_List : Choice_Ptr; end record; end filesel; with Java.Awt.Component, Java.Awt.Color; with Java.Applet.AppletContext; with Java.Net.URL; with Interfaces.Java; use Interfaces.Java; package body filesel is procedure init (Obj : access Filesel_Obj) is use Java.Awt.Component, Java.Awt.Color; Junk : Component_Ptr; begin setBackground (Obj, new_Color(255, 255, 128)); Obj.Format_List := new_Choice; addItem (Obj.Format_List, +"index.htm"); addItem (Obj.Format_List, +"adapple1.htm"); Junk := add (Obj, +"WEST", Component_Ptr (Obj.Format_List)); Obj.Download_Button := new_Button (+"Afficher"); Junk := add (Obj, +"EAST", Component_Ptr (Obj.Download_Button)); Validate (Obj); end Init; function action (Obj : access Filesel_Obj; Evt : Java.Awt.Event.Event_Ptr; What : Object_Ptr) return Boolean is use Java.Net.URL, Java.Applet.AppletContext; begin if Evt.Target = Object_Ptr (Obj.Download_Button) then showDocument (getAppletContext(Obj), new_URL (getDocumentBase(Obj), getSelectedItem (Obj.Format_List))); end if; return True; end action; end filesel; Annexe 3 : Spécification du paquetage Sockets (ANC) -------------------------------------------------------------------------------ADASOCKETS COMPONENTS ----S O C K E T S ----S p e c ----$ReleaseVersion: 0.1.3 $ ----- Copyright (C) 1998 École Nationale Supérieure des Télécommunications ----AdaSockets is free software; you can redistribute it and/or modify --it under terms of the GNU General Public License as published by --the Free Software Foundation; either version 2, or (at your option) --any later version. AdaSockets is distributed in the hope that it --will be useful, but WITHOUT ANY WARRANTY; without even the implied --warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. --See the GNU General Public License for more details. You should --have received a copy of the GNU General Public License distributed --with AdaSockets; see file COPYING. If not, write to the Free --Software Foundation, 59 Temple Place Suite 330, Boston, MA --02111-1307, USA. ----As a special exception, if other files instantiate generics from --this unit, or you link this unit with other files to produce an --executable, this unit does not by itself cause the resulting --executable to be covered by the GNU General Public License. This --exception does not however invalidate any other reasons why the --executable file might be covered by the GNU Public License. ----The main repository for this software is located at: --http://www-inf.enst.fr/ANC/ -------------------------------------------------------------------------------- with Ada.Streams; with Interfaces.C; package Sockets is type Socket_FD is tagged private; -- A socket type Socket_Domain is (AF_INET); -- AF_INET: Internet sockets (yes, should be PF_INET, but they hold the -- same value) type Socket_Type is (SOCK_STREAM, SOCK_DGRAM); -- SOCK_STREAM: Stream mode (TCP) -- SOCK_DGRAM: Datagram mode (UDP, Multicast) procedure Socket (Sock : out Socket_FD; Domain : in Socket_Domain := AF_INET; Typ : in Socket_Type := SOCK_STREAM); -- Create a socket of the given mode Connection_Refused : exception; procedure Connect (Socket : in Socket_FD; Host : in String; Port : in Positive); -- Connect a socket on a given host/port. Raise Connection_Refused if -- the connection has not been accepted by the other end. procedure Bind (Socket : in Socket_FD; Port : in Positive); -- Bind a socket on a given port procedure Listen (Socket : in Socket_FD; Queue_Size : in Positive := 5); -- Create a socket's listen queue type Socket_Level is (SOL_SOCKET, IPPROTO_IP); type Socket_Option is (SO_REUSEADDR, IP_MULTICAST_TTL, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP); procedure Setsockopt (Socket : in Socket_FD'Class; Level : in Socket_Level := SOL_SOCKET; Optname : in Socket_Option; Optval : in Integer); -- Set a socket option generic Level : Socket_Level; Optname : Socket_Option; type Opt_Type is private; procedure Customized_Setsockopt (Socket : in Socket_FD'Class; Optval : in Opt_Type); -- Low level control on setsockopt procedure Accept_Socket (Socket : in Socket_FD; -- New_Socket : out Socket_FD); Accept a connection on a socket Connection_Closed : exception; procedure Send (Socket : in Socket_FD; Data : in Ada.Streams.Stream_Element_Array); -- Send data on a socket. Raise Connection_Closed if the socket -- has been closed. function Receive (Socket : Socket_FD; Max : Ada.Streams.Stream_Element_Count := 4096) return Ada.Streams.Stream_Element_Array; -- Receive data from a socket. May raise Connection_Closed procedure Receive (Socket : in Socket_FD'Class; Data : out Ada.Streams.Stream_Element_Array); -- Fill data from a socket. Raise Connection_Closed if the socket has -- been closed before the end of the array. type Shutdown_Type is (Receive, Send, Both); procedure Shutdown (Socket : in Socket_FD; How : in Shutdown_Type := Both); -- Close a previously opened socket ---------------------------------- String-oriented subprograms ---------------------------------procedure Put (Socket : in Socket_FD'Class; Str : in String); -- Send a string on the socket procedure New_Line (Socket : in Socket_FD'Class; Count : in Natural := 1); -- Send CR/LF sequences on the socket procedure Put_Line (Socket : in Socket_FD'Class; Str : in String); -- Send a string + CR/LF on the socket function Get (Socket : Socket_FD'Class) return String; -- Get a string from the socket function Get_Line (Socket : Socket_FD'Class) return String; -- Get a full line from the socket. CR is ignored and LF is considered -- as an end-of-line marker. private .... end Sockets; Ada and the Internet: Information Linking, Agents and the scale of the Web Scott Arthur Moody Impact Systems Seattle, Washington, USA [email protected] 1. Web Surfing and Ada 95 Web “Surfing” has been used to describe how people interact with the internet. Having seen and participated in real surfing and wind surfing, I would have to say that the excitement factors are vastly different, favoring the real thing. But global accessibility aside, how can those of us that really enjoy distributed technologies also get as excited about the web? Enter the late 1990’s and the re-introduction of the Ada Language (Ada 95) now combined with an array of powerful support tools (many GNU based). Harnessing the Web can now be enhanced by using the powerful computing paradigms supported by Ada. One can get all the benefits of the traditional uses of a high performance and portable computing language (including debugger support) - combined with the ubiquitous interfaces provided through the Web. This presentation seeks to show some exciting uses of Ada and the Internet, especially uses of concurrent and distributed capabilities to cope with the scale possible with successful web ventures, and uses of web server tools such as Apache. “RealTime”, the other part of this weeks excellent conference is appropriate in context, since the web can challenge any architecture and implementation as the many real-world issues sneak in. This can range from the technical aspects such as millions of web-hits, or continuous operation with no down time, or vast intranets behind the firewalls of important institutions. Then solving something mundane like maintaining and changing the software through every aspect of the development cycle where cycles are definitely at the “speed of the internet”. 1.1 Enter Ada 95 and the Web Now take Ada 95 - still a relatively unknown language - one might ask how could it compete with the “true” languages of the web such as Perl and Java, or the server language C++? I think the answer to this lies in how the “internet” is defined. If one looks at the simple to complex web interfaces, tools like Perl and Java are appropriate. But look past this thin layer of webinterfaces. There could be an entire factory production line running or a host of distributed servers interfaces to distributed databases, or robots sending commands for visibility through the web, or maybe items in your home letting you know their status (i.e. getting low on food, everything is ok, baby sleeping, being robbed, etc.). The point being that the web and the internet are just one aspect of todays vast computing infrastructure. 1.2 Paper Outline This paper will highlight some specific concerns with privacy and consumer use of the internet. A new web addressing concept is introduced called a Digital Address. These digital addresses Ada and the Internet - Ada France 1999 are shown to support privacy with the added value of allowing subscription and publishing of consumer information (once privacy concerns are addressed). The architecture of “agents”, implemented in Ada, is shown along with a user access method of the Web, using an Apache server and embedded perl web content creation. Issues with “internet scale” are highlighted combined with some solution techniques. 2. Privacy and Spam Internet Concerns As an introduction to the application of Ada described in this paper, two specific issues with consumer use of the web need to be highlighted. In particular, consumer privacy and unwanted ‘spam’ email. Privacy is the #1 concern on the Internet today. This has been widely acknowledged in recent studies, including the May 24, 1999 special edition of The Industry Standard (http:// www.thestandard.net/metrics/display/0,1283,897,00.html). In particular this study noted that despite the fact that 66% of “.com” Web sites now post a privacy policy (vs. 4% one year ago), fear of spam (unsolicited commercial email) has actually increased to the point where 63% of Internet users (47.2M people) now fear getting spam from any online purchase. Spam is the most serious invasion of privacy for most Internet users. Spam has always been a serious problem for the Internet—by 1997, roughly one-third of the email message traffic AOL carries on any given day was spam. Now sophisticated new email address harvesting and bulk mailing programs are accelerating the problem. Almost 50 percent of e-mail users say they get spammed six or more times a week, according to a recent study of 13,000 e-mail users conducted by the Gartner Group. Infrequent email users whose email address lands on a spam list find that as much as 80% of their email is spam. And changing one's email address is only a temporary solution until the new address is harvested by spammers. 2.1 Product and Concept Solutions In an attempt to solve the privacy and spam concerns, a Seattle Internet company, Intermind 1 , has developed and patented a powerful new solution to Internet privacy. Intermind's U.S. patent #5,862,325, issued January 19, 1999, is the first patent in World Wide Web Consortium (W3C) history to be the subject of a press release seeking prior art (May 3, 1999). The W3C acknowledges it covers the essential elements of P3P (Platform for Privacy Preferences), a standard the W3C began developing a year after the patent was filed. 1. Thanks must be given to Drummon Reed, from Intermind and author of the pattents, for providing information on the digital address and privacy concepts. 1 of 5 August 22, 1999 The patent covers a breakthrough solution for spam—the digital privacy filter. A digital privacy filter works identically to the caller ID-based telephone privacy filters now being sold by all the major telcos, including Ameritech, GTE, US West, etc. With these filters, unrecognized callers (i.e., callers whose caller ID is not in the user's "accept" list, or who have caller ID blocked) are intercepted by a message saying this number does not accept solicitations. Solicitors are asked to hang up; other callers can press "1" to get through (or leave a message for further screening). A digital privacy filter is "caller ID for email". Installed either at the client (for POP3 email) or server (for IMAP or Web-based email), the filter compares each incoming message to the recipient's "accept" list (see the attached diagram). However unlike crude filters which simply delete messages from unrecognized senders, making email communications from new contacts all but impossible, a digital privacy filter sends a privacy message back to unrecognized senders. This message contains a link to the receiver's digital address agent—a Web server which displays the receiver's personal privacy rules to which the sender must agree in order to gain access to the receiver's email address. Although the receiver can customize these rules in any way, the most common standard rule is, "I do not accept unsolicited commercial email." Digital privacy filters are the first "killer app" for digital address service. Just as the telco's new privacy services are all based on caller ID, digital privacy filters are based on digital addressing. A digital address is a new type of address that combines all other types of addresses—email addresses, Web addresses, postal addresses, telephone numbers, fax numbers, etc.—into a single "smart" address for all digital communications. This is very similar to capability based systems[6] 2.2 History of Addressing Evolution of addresses: • 1800’s : delivery addresses (postal, parcel,telegraph) • 1900’s : telecom addresses (phone, fax, pager, cell) • 1980’s : email addresses (DNS names, IP addresses) • 1990’s : Web addresses (URL, URI) • 2000+ : Future Digital Addresses New addressing would be the same "abstraction layer" on top of any type of communications control data. An "active address" that can be associated with a resource. These addresses are objects with properties and methods; a platform for the active linking of information. One key drawback to the Web today is that links are passive, eg. they are designed to only transfer data when manually activiated by people. The next phase in the evolution of network com munica tions is for links to be come ac tive, e g. to automatically exhchange information when specified events occur at either end of the link. 2.3 Digital Addresses for Privacy Although privacy protection is the breakthrough benefit that will ignite initial demand for digital address service, digital addresses are a fundamental technological advance creating an entire "platform" for new products and services, much as the transition from character-based interfaces to graphical user interfaces created a new platform for personal computer applications. The benefits of the digital address platform include: H yp er-tex t N a vigation A u tom atic Info A gent u p d ates A G E N T m a na ged L in k D atab ase(x) S u b scriber(i) P u b lish er(a) d igital ad d ress p rivacy filters S u b scrib er(j) L in k D atab ase(y) P u blish er(b ) Tran sform a tion Figure 1. Persistent and Dynamic Link Management A digital address can be as simple as a name or phrase, in any language, so it is extremely easy to remember. To convey the simplicity and power of an address it can simply be your name (the only special syntax might be a leading "@" sign, e.g., @Bill Clinton, @Microsoft, @Gone With The Wind, etc.) • A digital address never has to change for the lifetime of its owner, no matter how often its owner changes email addresses, postal addresses, phone numbers, etc. • Digital addresses dramatically simplify data exchange. With an XML-based protocol (a superset of P3P), digital agents can automate the exchange of any data stored in the owner's digital profile. For example, users can literally "beam" contact data over the Web into other user's address books in one step. And using XML, profiles can be extended to cover any type of digital data, from email addresses to encryption keys to pizza preferences. • Digital address books can automatically synchronize data updates. Change any item of your digital profile—such as an email address or phone number—and the digital address book of every contact with whom you have linked that data will be updated automatically. Digital addresses support powerful new directory services. Using XML-based digital profiles, aliasing, and other architectural features, digital addresses will make it an order of magnitude easier for consumers and businesses to find each other. Digital addresses are particularly compelling for Internet mailing lists. Not only do they automatically assure list subscribers of the privacy of their email address, but they eliminate bounces due to bad email addresses by automatically sending a change-of-address message to the list server whenever the user changes a subscribed address. Intermind has confirmed the appeal of these advantages with several of the largest Internet discussion lists including Topica and SkyList, and has entered into letters of intent with TibBITS, one of the oldest and most influential Internet newsletters, and MessageMedia, one of the largest Internet email service bureaus with a volume of over 25M messages a month. • 2 of 5 SimpleGraphics Dynamic Web Page Creation modperl Tcl/Tk/Blt Perl External Addressing PHP SWIG coupling Personal Agent Link Agent Agent (core) Tree Addressing XML Tree Management Database Engines Figure 2. Schema Rules The architecture developed to manage the digital address and the user management of their published and subscribed information is shown in Figure 2. The “agent” is run as a server Visualization Apache Web Server httpd deamons P3P Privacy Rules 3. Agents and the Web process managing the users’ persistent information sources. The agent architecture is built through object hierarchies so additional capabilities can be added. In particular, the architecture supports “plug-in” rule processing. This is where a users’ P3P privacy rules, and other notification and data rules are inserted. The core agent manages these plug-ins, but also manages all XML tree manipulation. Rules Processing 2.4 Digital Addresses and Scaling for the Web Since todays web involves “passive link network”, the next phase will be a global platform for the active linking of information, or an “active link network”. Designing a new generalized address agent service, must include: • human friendly syntax • internalization (unicode) • large flat top-level namespace • extensible • privacy protection • active linking/caching The general architecture for management of bi-directional information management is shown in Figure 1. Publishers and Subscribers interact with each other by using their digital addresses which is controlled by their “agents”. Agents will manage the users’ privacy concerns while also keeping information content consistent. Without going into more implementation detail, the following high level questions must still be addressed: • How specifically will a digital addressing architecture distribute the load so the top-level namespace can support billions of names? • Given the much higher write activity of digital address/data agents than conventional directory entries, how can we make sure these writes are not a bottleneck? • How will the distributed architecture efficiently handle queries and update messages between digital address/link servers as the system scales to tens and then hundreds of millions of names? • Are there specific architecture choices that will support faced increase of digital address names over internet time? These are difficult questions but using high level toolsets that include concurrency and distribution, such as Ada, one can get a lot of real experience and architectural flexibility to deal with these scaling issues. “Distribution” makes for more exciting use of the internet and intranet, or at least lets users explore many runtime architectures without being tied to a single ‘web’ based interface. The typical web design supports returning static web content to users. A typical architecture uses a number of httpd web servers running on the same host, and when the scale increases, to add more host computers and load-balance requests to a nonbusy host and a free httpd process. A very popular server is from Apache and has heritage in the original NCSA servers. FreeBSD is also extremely popular because of it’s network support (and another reason for Ada GNU support on FreeBSD). Traditionally, this architecture is a relatively static web application - which is then complicated by the vast scale. But as this application gets more difficult - say managing data in a database, or performing autonomous actions on your behalf such as a proxy or agent - the existing computing bottlenecks are pushed past the web front-ends and into the “intranet” of your application domain. File Systems (XML) Agent Architecture Once outside the core agent, a number of added capabilities are required. The architecture is designed so the “web” is the not the primary interface. In fact, the web interface is just one of the ways to access the information. The goal is that testing of the agent server can be done at every level. This allows developers to leverage their power-tools, such as debuggers and runtime printouts. Debugging using the web is a non-trivial process. Some of the architecture issues include: • Accessibility of information (ui, web, palm pilots, tcl/tk, etc) - since the various access mechanisms keep growing, the architecture must support changing of interfaces easily. • Privacy and Notification capabilities, and how they would be added. It would be great if seamless ‘filter’ insertion (like the GLADE encryption filters) were used. • Scaling (through processes), including issues such as fault-tolerant agent-to-process servers, possibly using a multi-cast capability. • Information ‘transport’ issues - how does the information get passed between the various users (eg. http(s), xml(rpc/http), CORBA, GLADE, JavaRMI) • Personalization and programming of the agents and dealing with future agent mobility (eg. agent programming languages[1]). The Ada real-time toolset, including full object oriented features, concurrency, distribution and other “real-time” features are all needed to help solve these issues. 3 of 5 4. Apache, Perl and Ada Providing web accessibility to the agents was still one of the most important capabilities needed. This requires connection to a web server and providing a dynamic web content generation capability. Given the architecture described above, this had to be connected in some manner to the web - and then eventually support the scaleup desired. Dynamic web content generation is traditionally done from inside the web-server running with the Apache server, there are two good ways to get pre-loaded functionality: • Embedded Perl - where perl code is actually embedded inside HTML code. Execution can be increased since an Apache deamon will pre-load various parts of the perl code. Unfortunately, for development, the web code is hard to manage especially if using power HTML generation tools. • PHP - is a “C” like interface that is also embedded inside the HTML code. The advantage is that non perl programmers are happy, and the interface to a “C” server layer is one-to-one. The agent server, developed in Ada, then needed to be integrated to the web-content generation code. We figured this had to be possible, assuming we could get it to work through Apache and run on the machines of interest - FreeBSD and Linux. Thus there had to be some good interfacing mechanisms. Ada is about the only language I know that has a whole annex on how to “interface” to other languages. Also there is a standard way for the executable not to take over the “main” of the application, by providing initialization routines (try to do this with C++ in a portable manner). 4.1 SWIG Interfaces between Ada and Perl The Perl and C community have developed a number of interfaces between themselves, in particular the SWIG interface. SWIG takes a “C” header (.h) file and generates a Perl interface. Once an interface is made to “C”, we know that Ada can easily interface. So this system incorporates a thin layer of Ada to Perl via a SWIG “C-to-Perl” interface layer (actually SWIG is similar to marshaling/demarshling code since it actually converts a “char *” to a Perl string - and passing an Ada address via “char *” won’t convert correctly back to the address of the native language.) Then as the power of the Ada server is increased, the layer of Perl interfacing to the web can be decreased. For those that like Tcl/Tk - an equally powerful (or more powerful) web capability that could rival Java/Perl is also available - except for it’s obscurity and the non-pre-loaded plugins for tcl/tk in the common web browsers. Once the server was integrated, we had another “agent” testing option - the Web. Not relying only on this capability for testing helps ensure the integrity of the entire product. This is especially true with the Web, since errors are very unforgiving. In particular, errors will usually crash the web server, and debugging (using gdb) is very difficult. Also, any new capabilities requires taking down the web-server, relinking, and restarting. This can be difficult in an already running system. The other main advantage of using a high-level object-oriented language, like Ada, for the web server is efficiency. For example, the partial Ada XML parser and agent server would compile and link faster than the Perl+XML parser would run. 4.2 Concurrency and then Distribution for Scale As the architecture is expanded to handle the scale desired, practicing the various distributed interfaces will be crucial. Ask yourself how are you going to be sure the connectivity choices of the distributed application are correct or working? It would make sense to test these distributed interfaces in advance of full-scale deployment. Without a simple, or nearly seamless, language mechanism in support - which Ada 95 provides, it is harder for others in the computing field without these tools, to proceed. One reason is that they haven’t practised enough using current tools, before jumping in the deep-end of web-distributed. Development options for building the “distributed interfaces” vary, but can evolve in the following order, starting with the easiest to build and test. • build object interfaces and start testing in the same program. • add threads to model concurrency • use “seamless” distributed objects in Ada, to model real distribution • then can start building different external interfaces, including c-interface (maybe for the web) or IDL interfaces • Or soon can convert parts of the application to Java and interface that way. An ASIS assisted tool could also help build interfaces based on the current state of the user’ software. This could also help generate the SWIG interfaces. 4.3 Addressing using XML One of the goals of this project is to provide the digital addressing protocol in an “open-source” manner. Use of XML (eXtensible Markup Language) was chosen. It has many strengths especially if passing information throughout the web. In the XML internet world - there are a host of capabilities. These include DOM - the document object model, which includes a set of common API’s for traversing XML trees. These interfaces are useful, but getting past the retrieval of information from a tree, to the updates and management of that information, one must go deeper into the object definitions and control. This includes creation of class structures and then methods, refined operations, inherited capability - all the fundamentals of Object Oriented programming and programming languages. Management of the subscription and publishing information must have total traceability so when changes are made, the correct subscribers are updated. Thus we determined that a full addressing schema was necessary (since any depth of object could be addressable). For manipulation of the XML tree structure, a new Tree Arithmetic and addressing was defined. This is basically a “dotpath”, and can be seen the individual nodes of Figure 3. Since the nodes in the software are first-class addressable objects, new types were defined for addressing and all nodes have primitive methods returning their address. The other benefit was that since copying and pointing to existing data is such a common operation, copying sub-trees around between agents was needed. This involves copy and then re-numbering sub-trees. But the unique nature of the addressing made it possible to only change the root address, and keep the same tail address. It became very easy to test and debug tree manipulation software when code looked as easy as: new_address := old_address - old_root + new_root 4.4 Visualization of XML Trees Visualization of complex software applications is an exciting and challenging field. Useful displays are invaluable for developers in analysis of their software systems, and for meaningful system presentations to customers at a higher conceptual level. This was applied to visualization of XML trees. 4 of 5 Advanced visualization techniques combined with adaptable and extensible software architectures can help support manageable rapid application development. Looking at the tree normal compile-link-run language). By using Ada, and the new JGNAT (Ada to Java GNU/GNAT) capability, an Ada web server developer has an inexpensive Java entry for breaking past the java-or-not barrier. Now specific portions of an existing and tested application can be converted with no new code development. Looking at the agent and XML processing presented here, if a more “client” based web client is needed - this can be easily achieved. This is what we call a “local-agent”. In this specific case, if XML was sent to a client, the specific rule processing must still be performed. These rules are already codified in the Ada server processing. This same processing must be done by the client, so it makes sense to ship the actual code - thus shipping in Java would be attractive. It will be exciting to see all the uses of JGNAT as this new capability is released and widely used. 6. Future Work Figure 3. Agent XML tree representations in Figure 3., one sees the publisher/subscriber relation expanded into real data exchanges. In this implementation, using Tcl/Tk/ Blt and the multi-threading of Ada, interesting and semi animated visuals of the trees are achieved. (Also using tasks/ threads in a SimpleGraphics[5] framework, allows the graphic itself to have response time while the animation takes place.) Now what happens if the complexity of these links is increased ten fold, or more? Viewing that complexity will be difficult in 2D. So something like cone_trees, a 3D tree animated directory tree could be useful[2]. I cannot show or justifiably describe the animation achieved by Robertson, et al - in their vintage 1991 Cone Trees, and other 3D spacial views. But the most important feature is that their animation allows the user to keep the context of items that are leaving the field of view (moving to the hidden part of the tree) - but knowing they are moving away while other data is coming into view. Saving this context is of great value. Small changes, iterations, or gradual change, these help us cope with complexity. There is still a lot of design and real-experience needed to satisfy the scalability concerns. The next step is to handle the dynamic access of already executing “agent servers”. Some type of dynamic object registry is needed, one that can manage running or cached objects somewhere in the intranet. This seems an ideal use for the “shared-passive” Ada language feature especially if a multi-cast capability were implemented. There are still language issues since distributed Ada objects cannot be placed in “pure” partitions. Maybe the replication is not of the objects themselves, but the location of distributed servers? Another concern is that Ada isn’t an accepted language and where will programmers who know Ada be found? Then what about the “open-source’ community - won’t your tool look bad if the software is done in that rogue language, Ada, instead of Perl? Hopefully after enough real internet experiences are published, these concerns will be decreased. This will be especially true when the concurrency, distribution and real-time attributes are shown to be important for complex internet applications. In closing, I think its appropriate when talking with todays internet, to also think back to pioneers as far back as we can remember, but in our domain we can go back to our languages’ namesake: Augusta Ada Byron (1815 - 1852). Reading about her life and the “computer” concepts she understood is exciting[4]. I’m sure she would have relished first the telegraph (also called the Victorian Internet[7]) and then the real internet. References [1] S. Moody, “STARS Process Engine: Agents Artifacts and Activities”, TriAda 94. [2] Robertson, et al. “Cone Trees: Animated 3D Visualization of Hierarchical Information”. Proceedings SIGCHI 91. [3] M. Harrison, Tcl/Tk Tools, O’Reilly, 1997 [4] B. Toole, Ada: Enchantress of Numbers, Strawberry Press, 1992/ 98, http://www.well.com/user/adatoole 5. Java and Ada - JGNAT [5] S. Moody, et al. “Simple Graphics”, IRTAW-99, Ada Letters, June 99. Java adds another dimension to the web architectures. Mostly Java is used for web ‘client’ programs - albeit very large. As agent processes get more complicated, code mobility will be useful. This is where Java would be very useful. Currently developers must decide to develop their application in Java or another language. Thus their flexibility is hindered in some ways by Java. In particular, interfacing other technologies and languages with Java has been difficult (Java isn’t your [6] H. Levy, Capability-Based Computer Systems, Digital Press, 1984 [7] T. Standage, The Victorian Internet, Walker Publishing Company, 1998 More information on Impact Systems can be found at their web page: http://WhiteRiverRanch.com/impacts 5 of 5 CIAO Opening the Ada 95 Distributed Systems Annex to CORBA Clients Thomas Quinot École nationale supérieure des télécommunications 46, rue Barrault F-75643 PARIS CEDEX 13 France E-mail: [email protected] Abstract tion. No code specific to distribution needs to be written; the distributed application uses exactly the same native Ada data types as a non-distributed ones; local procedure calls are simply converted by the compiler to remote invocations. When an abstraction is made remote, no modification of its clients is required. CORBA [4], a set of industry standards promoted by the OMG consortium, is based on OMG IDL, a descriptive language whose syntax is close to C++, which is used to describe the services provided by a class of objects. IDL specifications can be mapped to different host languages such as C++, Ada 95, Java, or SmallTalk. A service developed in C++ can thus be accessed by clients written in Ada or Java, that run on entirely different platforms. The OMG has also standardized the protocols that are used for inter-node communication, theoretically allowing interoperation between products developed using tools from different vendors. While the Distributed Systems Annex of Ada 95 provides developers with a framework for easy contruction of safe distributed systems, integrating distribution seamlessly in the strong typing and well-defined semantics of Ada, it lacks the cross-platform, multiple-languages capabilities offered by CORBA. This paper presents CIAO (CORBA Interface for Ada distributed Objects), a tool for automated generation of proxies that allow CORBA clients to interact with services created using the Distributed Systems Annex. A representation of DSA service specifications in OMG IDL is first presented. We then describe an automated translation tool based on this representation model. This tool is based on ASIS, a standardized API for the extraction of syntactic and semantic information from an Ada compilation environment. It uses Broca, a full Ada ORB developed at ENST. CIAO and Broca are to be released as Free Software in the forthcoming months. 1 1.1 1.2 The CIAO project We have provided an in-depth comparison of the Distributed Systems Annex and CORBA in [5]. Our team has been researching solutions to take advantage of the safety of the annex, as well as of the emphasis put on code reuse and good software engineering practice by Ada, while opening distributed services to the multiple platforms and languages supported by CORBA. We have thus started the implementation of CIAO (CORBA Interface for Ada distributed Objects), a tool for automated generation of proxies between DSA services and CORBA clients. We see the development of CIAO as an opportunity to promote the use of Ada 95 as a competitive platform for the creation of distributed services. The principle of CIAO is to first generate an IDL specification that represents a service created using the distributed systems annex, and then automatically generate an implementation of this CORBA contract. In sections 2 and 3, we Introduction The Distributed Systems Annex and CORBA The Distributed Systems Annex of the Ada 95 standard [2] provides application developers with a framework for easy construction of distributed systems. It integrates distribution as a natural extension of the language’s abstraction paradigm. This allows applications developed using the annex to get the full benefits of the strongly typed programming model of Ada; the debugging of such applications is made very easy as well, because one can first write a system as a non-distributed, traditional Ada program, then later partition it and transform it into a distributed applica1 present a method and tool for the translation of a DSA service specification to IDL. In section 4, we then describe the automated implementation generator, and in section 5 we discuss the operation of the generated implementation. with the Pure category can also intervene in a service specification, because the Annex allows a Remote Types or Remote Call Interface to depend on a Pure unit. 2.2 2 2.1 Service specifications in distributed systems Specification of CORBA services The CORBA distributed programming model is more restrictive than the one of DSA. It is purely object-oriented: any service in a CORBA system is described in terms of objects that implement interfaces. The description of an interface, its associated data types and its operations together constitute an IDL specification. An IDL to host language translator is used to produce client stubs and server skeletons for the object. The generated stubs and skeletons depend on a particular Object Request Broker (ORB, the runtime component that implements the CORBA protocols) implementation. The mapping of IDL constructs to host languages is standardized by OMG. In the case of Ada 95, the mapping does not make use of the distributed systems annex; the IDL base data types are mapped to specific Ada types declared in a standard CORBA package, and object references are mapped to private tagged types that extend a root CORBA.Object.Ref type. Distribution is thus apparent and intrusive, because it is necessary to explicitly obtain object references in a CORBA-specific way, and to convert data types between the mapped IDL types and their native Ada counterparts. Specification of DSA services In Ada 95, abstraction between the interface (or specification) and implementation of a service (i. e. a set of data types and operation signatures) is provided by packages. The declaration of a package can contain, in particular, the declaration of data types and subprograms, while the body of the package contains the implementation of the subprograms. This imposes a clear specification of a functional module’s interface, and a complete separation between specification and implementation. The Distributed Systems Annex (DSA) naturally extends this model by allowing the programmer to specify that the interface defined by a specific package declaration is to be considered “remote”: several pragmas allow the definition of a category on a package, which indicates to the compiler that subprogram calls are potentially to be executed on remote hosts, and that objects declared using the types defined in the package may also reside on other nodes. The Remote Types pragma is used to define potentially distributed object types. When a tagged limited private type (e. g. type Foo is tagged limited private) and a corresponding class-wide access type (type Foo Ref is access all Foo’Class) are declared in a Remote Types package, then an instance of (a derived type of) Foo that resides on a given node can be designated by a Foo Ref value held on another node: such an access type is called a remote access to class-wide type (or RACW). A node that has a RACW which designates a remote object can invoke methods on that object; these method invocations are serviced using a remote procedure call performed by the Partition communication Subsystem (PCS), which is completely hidden within the compiler’s run-time library. To the programmer’s eyes, the behaviour of his application is exactly as though the object instance lived within the same process. The Remote Call Interface allows the creation of pure remote procedure call servers. When a library unit is categorized using that pragma, the Ada partitioning tool guarantees that the package is instantiated on exactly one node, and any call to a subprogram defined in that package made from any partition is treated as a remote call as well. The specification of a service in the DSA thus consists in the declaration of a package that has the Remote Types or Remote Call Interface category. Packages 2.3 Formal mapping of DSA specifications into OMG IDL In order to open access to DSA services for CORBA clients, we first have to represent the interface of such a service in CORBA’s specification paradigm. In other words, we have to translate the declaration of a DSA package into an IDL specification. To this effect, we have defined in [6] a complete formal mapping of such declarations into OMG IDL. That document precisely defines the translation of all legal DSA declarations into IDL abstract trees. The translation starts with the root Ada non-terminal, compilation unit. A compilation unit is mapped to an IDL <module>; subunits are mapped to nested modules. The declarations in a compilation units are likewise mapped to IDL declarations. More generally, the translation of an Ada construct is specified as an equivalent IDL element. When this element is a non-terminal of the IDL grammar, we then have to specify how its sub-elements are to be constructed. We give this construction in terms of the translations of other Ada elements, and thus recursively define a translation for all valid constructs that can be encountered in a DSA package declaration. Most Ada types are mapped to their “natural” IDL counterparts: numeric, enumerated, boolean, and string types are 2 translated to the corresponding IDL constructs. Ada records are translated to IDL struct types. The members of that structure type are the respective translations of the component declarations of the Ada record. Variant records are represented using structures and unions, and arrays are represented as sequences. Some Ada types have semantics that are inherently local to the node that created them. This is the case, for example, for non-remote access types, as well as limited types. The Distributed Systems Annex mandates that such a type shall have user-defined marshalling and unmarshalling subprograms if they are to be used in the specification of a DSA service. In the CORBA translation of a service, these types are represented as opaque sequences of octets. A CORBA client can thus obtain a value of those types, and send it back unchanged to a DSA server. Potentially distributed objects are declared in Ada as tagged limited private types. Such a type is mapped to an IDL interface declaration. The methods of this interface are translated from the declarations of the Ada type’s primitive operations. Since the “self” parameter of object methods (which designates the object instance that is the target of the call) is implicit in IDL, we omit the first controlling formal parameter of all primitive declarations for distributed object types. We have thus defined a complete translation of all legal Ada constructs in OMG IDL. The only exceptions are renaming declarations and generic instantiations. These are not taken into account in the current translation, because they introduce complex visibility and name resolution problems; we therefore decided to concentrate on getting a first operational version of the translation without these constructs. 3 are built in the compiler; it provides an easy access to the syntax tree and associated semantic information built by the compiler from a compilation unit. ASIS standardizes a set of queries that allow an Ada program to manipulate the syntactic information corresponding to another Ada program: for a given Ada element, it gives access to its children element; a systematic recursive traversal iterator is provided, as well as queries that allow the user to explicitly obtain specific children elements of an element. These are the ASIS syntactic queries. A set of semantic queries is also defined. These functions provide information about the semantic relationships between elements. For example, from an element that is a usage name for an entity, they can provide the definition of that entity. We thus can view ASIS as a reflexivity interface for Ada. The CIAO DSA to IDL translator uses ASIS. This makes it independent of any particular Ada compilation environment, although it is developed primarily with the GNAT compiler, and the associated ASIS-for-GNAT implementation. GNAT [8] is a free software Ada compilation environment initially developed at New-York University and now maintained by Ada Core Technologies1 . 3.2 3.2.1 Overview The CIAO Translator [7] uses ASIS to extract syntactic and semantic information from the GNAT Ada 95 compilation environment. The program is easily portable to any other compilation environment that supports ASIS, for it does not depend on compiler internals, but only on some utility libraries that come with GNAT in source form. The operation of the translator has two main phases. The Ada semantic tree is first recursively traversed using the standard ASIS iterator, ASIS.Traverse Element. This is a generic iterator that provides a framework for a systematic recursive, depth-first traversal of an Ada syntax tree. The internal state of the traversal functions includes the IDL syntax tree being constructed, as well as a “current position” pointer designating a node in the tree. When an Ada element is encountered that must be translated, a new node is created and becomes the current node. The children of the Ada element are then explored, either explicitly using ASIS syntactic queries, or implicitly as a result of the continuation of the iterator. When an element is processed, its translation is attached as a subnode of the current node. When the whole Ada tree has been explored, we have an in-memory image of an IDL abstract tree. This tree gets decorated with semantic information, to allow the implementation generator to obtain sufficient information about Implementing an Ada to IDL translator Having established a model for the translation of DSA service descriptions into OMG IDL specifications, the CIAO project continued with the development of a translator that implements this model. In this section, we first present a standard library for Ada CASE tool construction, then discuss the implementation of our DSA to IDL translator using that library. 3.1 The CIAO translator The Ada Semantic Interface Specification ASIS [3] (Ada Semantic Interface Specification) is an open, published, vendor-independent API for interaction between CASE tools and an Ada compilation environment. It defines the operations needed by such tools to extract information about compiled Ada code from the compilation environment. The ASIS interface allows the tool developer to take advantage of the parser and semantic analyser that 1 See 3 http://www.gnat.com/. package Gizmos is pragma Remote_Types; Ada 95 syntactic and semantic information CIAO application type Root_Gizmo is abstract tagged limited private; CIAO translator subtype Celsius is Float range −273.15 .. Float’Last; type Price is digits 5; OMG IDL syntax tree type Gizmo_Params is record Temperature : Celsius; Cost : Price; end record; CIAO generator IDL Impl procedure Heat (Self: access Root_Gizmo; How_Much : in Celsius); function Get_Params (G: in Root_Gizmo) return Gizmo_Params; OMG IDL source text IDL to Ada translator (AdaBroker) Proxy packages CORBA server skeleton type Electric_Gizmo is new Root_Gizmo with private; function Is_Plugged_In (Self: access Electric_Gizmo) return Boolean; CORBA server implementation Figure 1. Flow of information through CIAO private −− Private part omitted. end Gizmos; the translated DSA service. Once this IDL tree is constructed, a trivial recursive traversal is performed, in order to produce the corresponding IDL source file. This merely consists in descending the tree depth-first, emitting a textual representation of each node as it is traversed into an output file; see samples 1 and 2 for an example of the translation. The last phase consists in the generation of the CORBA implementation. The code generator is driven by the IDL tree, and uses ASIS queries to retrieve supplementary information about the structure of the DSA service from the Ada environment. Figure 1 summarizes the flow of data through CIAO tools. 3.2.2 Sample 1: Example DSA package Gizmos Translator uses numerous ASIS queries to obtain the descriptions of the Ada elements to be translated. Some of the Ada tree is simply traversed according to the default depthfirst traversal provided by the standard iterator. On the other hand, for some particular elements, this default systematic traversal is inappropriate. Some parts of the Ada tree are to be ignored in the translation. For example, the private part of a DSA package declaration does not define a service provided by that package to exterior clients, and is therefore not translated. Similarly, the “self” formal parameter of distributed object methods is implicit in IDL, and must be omitted. In these situations, we explicitly use ASIS syntactic queries to explore the Ada tree, and bypass the default traversal. We also make use of semantic queries, most notably for the resolution of entity usage names. The ASIS implementation has access to the Ada abstract tree as constructed and decorated by the compiler. All the name resolution and visibility rules are thus already applied; from any usage name, we can immediately obtain the corresponding defining oc- Construction of the IDL tree The overall structure of CIAO is presented on figure 2. The main procedure, Driver, initializes the ASIS environment, then schedules the different translation and code generation phases. The first phase consists in the production of the IDL abstract tree from the DSA package declaration. This is the responsibility of the Translator package. This package essentially contains an instantiation of the generic Traverse Element iterator, and defines the function that maps an Ada element into its IDL translation, as defined by the formal translation model. 4 Functional blocks #include "ciao.idl" CIAO.Driver module CORBA__Gizmos { interface Root_Gizmo; typedef double Celsius; CIAO.Translator typedef double Price; typedef struct Gizmo_Params_struct { Celsius Temperature; Price Cost; } Gizmo_Params; CIAO.ASIS_Queries CIAO.Generator IDL Impl CIAO.IDL_Syntax Asis CIAO.IDL_Tree Ada 95 compilation environment OMG IDL syntax tree interface Electric_Gizmo; interface Root_Gizmo { void Heat (in Celsius How_Much); Gizmo_Params Get_Params (); }; Figure 2. Structure of CIAO the nodes using a higher-level package, IDL Syntax, which enforces the IDL grammar rules. Each node also includes semantic flags, as well as a pointer to the original Ada element. This attribute is essential for the implementation generator, because it establishes a “bridge” between the semantics of the IDL contract and that of the DSA service. interface Electric_Gizmo : Root_Gizmo { boolean Is_Plugged_In (); }; }; 4 The implementation generator Sample 2: Generated IDL for Gizmos The next step in the CIAO processing is the generation of an implementation for the constructed IDL specification. Using a standard IDL to Ada compiler, the source file created by the translator can be mapped to CORBA client stubs and server skeletons. The skeleton for an interface contains the declaration of an abstract tagged type whose primitive operations correspond to the methods of the interface. The server developer must then produce an implementation type, which extends the skeleton type and overrides its primitives with actual implementations. In the context of a CORBA to DSA proxy, these actual implementations must convert the parameters of the method invocation from CORBA mapped types to native Ada types (which are used in DSA calls), then perform a DSA remote call and possibly convert back a return value. For CIAO, we have produced a code generator that automatically creates the implementation for interfaces generated by the translator described above. These implementations are targeted to the Broca CORBA toolkit, a free software ORB and IDL-to-Ada compiler developed at ENST [1]. As Broca implements CORBA’s Portable Object Adapter, there is very little code in CIAO that actually currence, and thus the denoted entity. The translator needs to know of some high-level semantic properties that are defined in the language reference manual, but have no corresponding ASIS queries. For example, in order to translate a subprogram declaration in a Remote Types package and associate it with the proper IDL interface, its controlling formal parameters have to be determined. To address this requirement, we have created a set of “extended” ASIS queries that correspond to properties formally defined in the Ada standard, and we have isolated them in a package (ASIS Queries) that can be reused independently of the CIAO project in any ASIS tool that would need access to these properties. We have also designed a library for manipulation of IDL abstract trees. We based it on existing components for syntax tree data types: this library is an adaptation of parts of the GNAT compiler, which were modified to handle IDL nodes rather than Ada nodes. Like the original, this library has two layers. IDL Tree provides low-level access to a “universal” node structure. Other packages only access 5 depends on the ORB implementation, and we consider the generated code to be fairly portable to another CORBA implementation. This generator is driven by the IDL abstract tree, because the structure of the produced code corresponds to the layout of the IDL specification as a set of nested modules of interfaces. Semantic information from the Ada environment is also used for the construction of the necessary parameter type conversions, constraint checks, and DSA method invocations. Indeed, a lot of semantic information is lost during the translation of DSA specifications to IDL; IDL has a far less expressiveness, and cannot represent such concepts as subtypes or constrained types. Consequently, the code generator uses annotations inserted in the IDL tree by the translator that point back into the Ada tree, and uses ASIS to complete the code production. The generator also produces conversion packages for data types that are declared in the DSA packages: when a native DSA type is translated to IDL, the mapped type used by the IDL to Ada compiler is different from the original type. For example, an Ada String, translated to an IDL String, will be mapped back as a CORBA.String. We therefore produce subprograms to convert data back and forth between the two type sets. These functions are used in the generated implementations to convert the call arguments and return values. 5 5.1 RACW CORBA bus Partition 1 Partition 2 DSA object CORBA DSA object 2. Mapped DSA call Client Application CORBA glue 1. CORBA call ORB Proxy partition Figure 3. Calling DSA objects from CORBA (37.0), a CORBA request is sent to the proxy partition’s ORB. The ORB looks up the IOR in its internal tables, and calls the Heat method on the CORBA implementation object for interface Gizmo. This method first checks that the provided actual for parameter How Much satisfies the constraint on subtype Celsius. The implementation object has an internal variable which is a RACW Self Access designating the actual DSA object. After the constraint check is made, the Heat subprogram uses this RACW to perform a dispatching call to Heat (Self Access, 37). This call may or may not be remote, depending whether the user has chosen to affect the proxy package on the partition where the DSA object instance was created. The run-time operation of the proxy Execution of calls 5.2 For each DSA package, we have automatically generated a CORBA skeleton package, using Broca’s IDL to Ada compiler, and a matching implementation package, using the CIAO code generator. These packages together constitute a “proxy” that acts as a gateway between CORBA clients and DSA servers. Using a partitioning tool such as Gnatdist, the user can then assign the proxy packages onto a partition in her DSA application. That partition is then linked with the Broca run-time library, and behaves as a CORBA server. It may receive requests from CORBA clients; these requests are serviced by calling the generated implementation subprograms, which in turn call the original DSA operations. The structure of such a distributed application is summarised on figure 3. Suppose for instance that a CORBA client has obtained a CORBA object address (an IOR, Interface Object Reference) My Gizmo that designates a DSA object of type Gizmo’Class. The type of this IOR is the CORBA mapped interface Gizmo. As far as CORBA is concerned, it designates some object that is managed by the ORB on the proxy partition. When the client makes a call to My Gizmo.Heat Creation of object references We have discussed the operation of the proxy from the point where CORBA clients have obtained IORs that designate DSA objects; we still need to provide a mechanism for assigning an IOR to a DSA object. For this purpose, we take advantage of the Portable Object Adapter facility integrated in Broca. In a CORBA system, the Object Adapter (OA) is the software component that implements the management of the entities that incarnate CORBA Objects, and enforces policies over their creation, activation, deactivation and destruction. In former CORBA versions, only one OA existed: the Basic Object Adapter (BOA). In the BOA, exactly one unique implementation object exists for each CORBA object reference. The POA introduces much more flexibility in the design of a server: it allows a server to contain only one implementation object for a whole class of CORBA objects; within a method invocation, standard function calls to the ORB provide a way to identify the specific instance which is the target of the call, using a user-assigned identifier which is embedded in the object reference. CIAO uses this policy for the implementation of interfaces that represent Ada distributed objects. The object 6 identifier that we chose is simply the marshalled form of a RACW (a DSA object reference) that designate the object. Each time one such reference is to be transmitted to a CORBA client, we construct an IOR by associating that object identifier with the POA created at initialization time by the proxy for the class of the object. There is no need to register that newly-created IOR with the ORB, thus avoiding any run-time memory leak. Since the RACW can be computed back from the IOR, there is no need to maintain a record of the mapping between DSA objects and IORs: the proxy is stateless, and can be stopped and restarted without loss of functionality in case of a fault. The POA thus permits the creation of CORBA object references that correspond to RACWs. Remote Access to Subprogram types can designate distributed subprograms; these are conceptually equivalent to objects with no attributes, and with a single operation, Invoke. We can thus treat RAS types likewise, as a particular form of object references, and handle them in a similar fashion to RACW types, once more using the marshalling and unmarshalling functions provided by the Annex. Remote Call Interface packages are much simple to handle; since each RCI package is instantiated only once in a complete DSA application, only one object reference for its CORBA implementation object is needed. In the case of RCIs, the POA is thus used in its mode of operation that is closest to the BOA: a single implementation object is created, and it is activated and assigned a reference by the ORB at proxy start-up. 5.3 CIAO proxy 3. Forwarded call 4. Return DSA object ref. RCI package 1. Register RCI interface 4. Forwarded return value CORBA Naming Service 3. Call RCI 2. Provide reference to RCI RCI has a DSA reference RT package CORBA client 5. Client can invoke method on object Distributed object instance Figure 4. Bootstrapping a CIAO application terface; the proxy packages automatically registers the corresponding objects with the CORBA naming service at start-up time. In this scheme, CORBA clients can obtain references to the RCI packages by querying the CORBA Naming service, and then request objects from RCI servers just like normal DSA clients. We thus naturally transport the DSA model of operation into the CORBA world, by making the procedure for getting initial references to RCI packages explicit (whereas it is implied in DSA). An example of this protocol is given on figure 4. If the application was purely based on DSA, then at startup a node would only be able to make remote calls to the RCI package. This is how it would obtain references to objects that live on other partitions. When the CIAO proxy is started, it creates a CORBA implementation object for the interface of the RCI package, and registers a reference to this object with the CORBA naming service (1). A CORBA ORB provides a method by which a CORBA client can obtain an initial reference to the naming service. The client can then query the naming service and obtain the reference to the RCI package (2). This reference is used to perform a remote call on the RCI package (3), which finally returns a reference to a DSA object (4). The CORBA client can thus invoke a method on the DSA object (5) just as any DSA node could. Initial distribution of references In distributed systems, initially obtaining a distributed object reference may be difficult. It is often necessary to query a distributed naming service to obtain object references, but it is impossible to use the naming service to retrieve its own root reference. In DSA, an object reference can only be created when a value is transported (as a remote call parameter, or as a remote function return value); when an object is created on a partition, the only way for a client partition to obtain a reference to that object is to get it as a value returned by a remote call, i. e. as the return value or as an out mode parameter of a RCI or RAS call, or RACW primitive operation call. Initially, clients always obtain their first object reference using RCI calls, because RCI have a fixed, well-know position within the distributed application; the Partition Communication Subsystem includes its own “hidden” mechanism for name resolution, and initially provides a means for any partition to make a call to any RCI package. In CIAO, we have thus decided to solve the “chicken & egg” problem in the following way: RCI packages are mapped to modules with a single Remote Subprograms in- 6 Conclusion The Distributed Systems Annex provides a superior framework for the development of safe distributed applications. It is well-integrated in the Ada software engineering practice, and allows for an easy transition from nondistributed to distributed code. CORBA, on the other hand, emphasises interoperation between objects created and residing on different platforms, written using different languages, and different CORBA implementations. 7 We proposed a solution to make the best of both worlds: the tools presented here allow a CORBA client to access services provided by DSA objects and servers. It makes use of ASIS, an ISO standardized API for Ada CASE tools. It is based on free software components developed by ENST and others, and will be made freely available in source code in the near future. References [1] T. Gingold. Broca, an Ada CORBA implementation. Master’s thesis, ENST Paris, July 1999. [2] ISO. Information Technology – Programming Languages – Ada. ISO, Feb. 1995. ISO/IEC/ANSI 8652:1995. [3] ISO. Information Technology – Programming Languages – Ada Semantic Interface Specification (ASIS). ISO, 1998. [4] Object Management Group. The Common Object Request Broker: Architecture and Specification, revision 2.2. February 1998. OMG Technical Document formal/98-07-01. [5] L. Pautet, T. Quinot, and S. Tardieu. CORBA & DSA: Divorce or Marriage? In Proceedings of AdaEurope’99, Santander, Spain, June 1999. [6] T. Quinot. Mapping the Ada 95 Distributed Systems Annex to OMG IDL — Mapping definition. Technical report, ENST Paris and university Paris VI, May 1999. [7] T. Quinot. Mapping the Ada 95 Distributed Systems Annex to OMG IDL — Specification and implementation. Master’s thesis, ENST Paris, Aug 1999. [8] E. Schonberg and B. Banner. The GNAT project: A GNUAda 9X compiler. In Proceedings of Tri-Ada’94, Baltimore, Maryland, USA, 1994. 8 JGNAT The GNAT Ada 95 environment for the JVM Emmanuel Briot [email protected] ACT Europe Summary GNAT-to-JVM Compiler Tools, Debugging, Distributed Systems Interoperability Mapping Java to Ada Example: Tic Tac Toe Applet Anything special about the Java programming language ? Java Language Ada Java Virtual Machine APIs and Libraries 4Java is very Ada friendly 4JVM is an excellent Ada platform 4Java APIs are a fundamental component of the technology GNAT to JVM Compiler ACT has a tradition of ... 4Doing 100% Ada 95 implementations Ð core language Ð all Annexes Ð 100% validations 4Using Ada 95 to develop its products 4Sources available under GPL license 4Implement 100% Ada 95 (core + annexes) Ð in particular implement all the Ada library (Ada .Text_IO, ...) Ð certain features have no impact on generated code (e.g. some representation clauses, É) Ð full Real Time Annex compliance if underlying JVM supports it (thread priorities, É) 4Implemented entirely in Ada 95 4Main design document available 4100% sources available under GPL license Very Natural Mapping between Ada 95 & JVM ADA scalars arrays records tagged types packages subprograms default initializations exceptions JVM primitive types arrays final classes classes classes (sometimes packages) methods constructors exceptions The JVM makes it easy for ... 4No memory layout needed 4Stack machine for computations 4OO model built in 4Exception model built in 4Protected record-like mechanism built-in 4Index checks for free 4Null-dereference checks for free Extra work needed for 4Deep copy operations (x := y) 4Access to subprograms 4Nested subprograms (static chains) 4Pass slices by copy makes your life simpler É. Fortran Java C++ C Front Ada ends GCC target machine code Backend target independent target description x86 PowerPC 68K MIPS Sparc Alpha i960 IA-64 HP-PA É Unix VMS NT OS/2 VxWorks ÉÉÉ The GNAT JVM Backend Ad a Ada GNAT GIGI GCC Ada GNAT Jexpand Machine code Java Code Gen. bytecode 1. expands some Ada constructs GNAT front-end 2. makes calls to JVM code generator Juggler High-level JVM interface Low-level bytecode interface Javelin Class file generator Bytecode Generator GNAT JV M back end 1. JVM instruction selection 2. JVM peephole optimizations By te co de GNAT & Ada 95 Tasking yo u r Your code Ad a ap High-level tasking services pl GNARL i c Gnat runtime at io GNULLI n Target independent Windows NT OS/2 Solaris VxWorks low-level tasking API GNAT runtime & JVM Ü Each Ada task maps onto a Java thread Ü Ada code with tasks can call Java code with threads & conversely ! Ü Lock/unlock map onto JVM monitor operations Ü Task priorities map onto Java thread priorities, but... Ü Most GNULLI primitives map nicely into JAVA thread ops Your code GNARL JVM GNULLI a d A 95 e d co GNARL_Op1(..); GNARL_Op1(..); GNAT expander GNARL_Op2(..); GNARL_Op2(..); GNARL_Op3(..); GNARL_Op3(..); GNARL interface Target independent GNARL body GNULL interface Target dependent GNULL body JVM ops + Java API Prototype Implementation 4ALL CORE tasking tests passed (on every pure Java JVM implementation) 4Ada RT Annex Tests: Ð JDK 1.1.4: several tests failed Ð JDK 1.1.5: most Annex D tests passed on Solaris JVM (native threads) 4JGNAT guarantees real-time Ada 95 semantics on JVMs with real-time behavior Tools Some JGNAT Tools... 4 jvmstrip Ð Strips all debugging info from .class files 4 jvmlist Ð Ð Displays class file contents Embeds original source into class bytecode 4 jvm2ada Ð Ð produces an Ada spec from any class file allows transparent use of any Java API from Ada Other GNAT Tools... 4jgnat, jgnatmake, jgnatbind, jgnatlink Ð Standard GNAT tools available 4gnatxref, gnatfind, gnathtml 4gnatprep Ð GNAT preprocessor 4gnatstub Ð Generate stubbed compilable bodies from specs 4gnatelim Ð Detect and eliminate unused subprograms on a complete partition 4 É. Symbolic Debugging GNAT leverages on existing tools 4Any pure Java debugger works with GNAT 4Debugger needs specialization for Ada 95 to Ð display data in Ada 95 format Ð understand Ada 95 syntax Ð switch between Ada tasks conveniently JVM debugging technology debugger JNI JVM Debug API sockets Could be same machine JNDI your app JNI JVM JNDI = Java Native Debugging Interface Debugger need not run on a JVM De bu gg er JNDI JNI App JVM JNDI = Java Native Debugging Interface De bu gg er debugging in a cross environment sockets JNDI JNI App JVM The GNAT Debugger command parser output formatter low-level debugger Target dep. hooks Distributed Systems GLADE GNATÕs Distributed Systems Annex 4Management of communications between Ada partitions 4Tools to define partition location & content * Heterogeneous Communication * Data filtering (encryption, compression) * Replication Capabilities * Embedded Capabilities Ada 95 Distributed Sys Annex & the JVM LA D E Ada E G G LA D Ada J VM GLADE Ada Interoperability Java Language Ada Java Virtual Machine APIs and Libraries 4Java is very Ada friendly 4JVM is an excellent Ada platform 4Java APIs are a fundamental component of the technology ACT has a tradition of ... 4Full adherence to platform-specific ABI ¥ ¥ ¥ calling sequences object code format debugging information 4Full interoperability with other languages 4Full access to libraries written in other languages Full JVM Interoperability This means that ... 4GNAT is highly compatible with existing JVM tools & environments 4Tools may need specialization for Ada 95 but do not need rewriting 4Full transparent access to Java API 4Full Java interoperability Ð Access any Java services from Ada Ð Use Ada services from Java Ð Ability to extend Java classes or Ada tagged types across languages Ð Ability to propagate and catch exceptions across languages 4New interfacing pragmas Ð Import/Export (Java,É)/... Mix and and match match Mix and Java Java AAddaa and as the the developer developer as sees fit fit sees Important Remark Java Language Transparent Ada Java Virtual Machine Example: GNAT for Java Demo Ada Ada GNAT for Java Java socket interface Java Bytecode Ada RT code Full interoperability with Java & its API 2 independent threads Java Language Ada Java VM Java API Java serial port interface UI G va Ja jvm2ada Java Language Ada Java Virtual Machine APIs and Libraries jvm2ada 4100% Java-to-Ada API conversion tool 4Absolutely no manual intervention 4Works on EVERY Java library 4Distribute the tool NOT Ada bindings 4Java-to-Ada mapping works whether Ada code is on the JVM or on native machine JVM & the native world JNI JVM API JNI = Java Native Interface JVM & Native Interoperability Java Language Ada same pragmas Ada Ada pragmas JNI Java Language JVM API Other Language What about ?same pragmas Ada Other Language C, Fortan, É Ada pragmas JNI Ada JVM API Wherever your Ada code runs Ada a d A " s e it v ma a ag n " pr Other Other Language Language C, ,É C, Fortan Fortan, É JVM "n at pr ive" ag A m da as Java Language Ada & Java Interfacing Summary 4Tool for automated interfacing (jvm2ada) 4Mapping Java classes to Ada packages 4Pragma Import and Convention 4Handling circularities 4Implicit conversions 4Support for Java interfaces 4Mapping Java to Ada Automated Interfacing to Java Using jvm2ada 4Using Java APIs from Ada should be easy 4All API functionality must be available 4jvm2ada generates Ada specs from Ð .class, .zip and .jar files 4No hand-editing of Ada required 4Can map ALL Java classes onto Ada packages 4Handles circularities in Java API classes 4Supports Java interfaces and constructors Mapping Java Classes to Ada Packages 4Each Java class is represented by an Ada library package 4The Ada package contains a single tagged type with components and primitive operations 4Uses pragmas Import and Convention 4Java-specific pragmas for interfaces and constructors 4Java packages and nested classes use child units Pragma Import and Convention 4Pragma Import (Java, entity_name, [external_name]) Ð On packages (JGNAT maps to a Java class) Ð On subprograms (JGNAT maps to a Java method) Ð On variables (JGNAT maps to a static field) 4Pragma Convention (Java, entity_name) Ð On a tagged type (JGNAT maps to a Java class) Ð On a subprogram (JGNAT uses Java conventions) Direct Mappings 4Abstract Classes & Methods 4Static Methods and Static Fields 4Native Methods: pragma Import (C, É) 4Final Fields: constants 4Volatile Fields: pragma volatile Classes public class F o o { public int F i e l d; public void S o m e _ O p (int p) {É} static public int V a r; static public int F u n c (Foo obj, F o o [ ] b) return i n t ; } Using FooÕs services in Ada public class F o o { public int F i e l d; public void Some_Op (i n t p) {É} with Java; use Java; static public int Var; with F o o; use F o o; o static public int F u n c (Foo obj, F o o [ ] b) return int; procedure Client i s O b j : F o o.Ref := new_F o o; o o A : F o o.Arr := new F o o.Arr_ObjÕ(0 .. 9 => 2 2 ) ; o o X : i n t := F o o.F o u n c (O b j, A); begin S o m e _ O p (O b j, X); O b j.Field := 22; F o o.V o a r := 3; end Client; with Java.L a n g.Object; use Java.Lang.Object; package F o o is type T y p is new Java.L a n g.Object.Typ with record Field : Integer; public class F o o { end record; public int F i e l d; type Ref is access all TypÕClass; public void Some_Op (i n t p) {É} static public int Var; type Arr_Obj is static public int F u n c (Foo obj, array (Natural range <>) of Ref ; F o o [ ] b) type Arr is access all A r r _O b j; return int; procedure Some_Op (This : access T y p; P : Integer); function new_ F o o (This : Ref := null) return Ref; V a r : Integer; function Func (O b j : access TypÕClass; B : Arr) return Integ e r ; end Foo; Handling Circularities public class Object { ... public S t r i n g toString (); } public final class S t r i n g { ... public static String valu eOf (O b j e c t o b j) ; } with type with type j a v a.l a n g.String.Ref is access; package java.lang.Object is type Typ is tagged limited private; function toString (This : access Typ) return j a v a.l a n g.String.Ref; ... end java. l a n g.Object; with type j a v a.l a n g.Object.T y p is tagged; with java. l a n g.Object; package java.lang.String is type Typ is new java.lang.Object.Typ with null record; type Ref is access all TypÕClass; function valueOf (Obj : access j a v a.l a n g.Object.TypÕClass) return Ref; end java.lang.String; Client Code with Java.Lang.Object; with Java.Lang.String; procedure Client is O b j : java.lang.Object.Ref := ...; Str : java.lang.String.Ref := toString (Obj) ; ... Implicit Conversions 4Problem: Java more weakly typed than Ada 95, making use of access types cumbersome 4Java: Ð Allows freely passing objects to parent operations Ð Null may be passed to non controlling arguments 4Ada 95: Ð Can have many access types (e.g., one per tagged type) Ð Named access type parameters do not allow implicit conversions Ð Access parameters allow implicit conversions, but restricted in use (null actual causes exception) Possible Solutions 4Relax Ada rules for passing null to access parameters (for Java-convention subprograms) Ð Problem: Not clearly legitimate semantics 4Syntactic GNAT-specific language extensions Ð Special syntax for "open" access types that allow implicit conversions Ð Problem: Non standard extension 4Official language extension as part of with type Ð Implicit conversions allowed for all general access types (access all, access constant) Ð Problem: Might cause ambiguities (incompatibility) Java Specific Pragmas 4Java_Interface 4Java_Constructor Java Interfaces 4Java interface types allow a nice form of multiple inheritance not supported by Ada 95 4A Java class may "implement" multiple interfaces, inheriting and overriding interface methods 4Ada tagged types can only extend from a single parent 4Java API classes depend on interfaces 4Generic mix-ins are a possible mechanism, but unwieldy Using Java Interfaces from Ada 4A Java interface is mapped onto an abstract tagged type with abstract operations (pragma Java_Interface) 4The tagged type has a single access discriminant: type Some_Interface (Self : access Java.Lang.Object'cl a s s) is new abstract J a v a .L a n g.Object with null recor d ; pragma Java_Interface (Some_Interface); 4Other tagged types can implement one or more Java interfaces 4Implementing type overrides operations of its parent interface types type Interface_User (I_Some_Interface : access Some_Interface'class; I_Other_Interface : access Other_Interface'clas s; ... etc.) is new Parent_Type with ...; Java_Interface with Java.Lang.Object; use Java.Lang.Object; package F o o is type Typ (Self : access Object.TypÕClass) is new abstract Object.T y p with null record; pragma Java_Interface (Typ); type Ref is access all Typ'Class; procedure Proc (This : access Typ; Val : Float) is abstract; function Func (This : access Typ) return Float is abstract; end Foo; Using a Java Interface with Java.Lang.Object; use Java.Lang.Object; with F o o; package Bar is type Typ (I _F o o : access Foo.TypÕClass) is new Java.Lang.Object.Typ with record Field : Integer; end record; type Ref is access all Typ'Class; procedure Proc (This : access T y p; Val : Float); function Func (This : access T y p) return Float; end Bar; Conversions with Java.Lang.Object; use Java.Lang.Object; with Foo; package Bar is type Typ (I _F o o : access F o o.TypÕClass) is new Java.Lang.Object.T y p with record Field : Integer; end record; type Ref is access all Typ'Class; procedure Proc (This : access T y p; Val : Fl o a t ) ; function F u n c (This : access T y p) return Float; end Bar; with Java.L a n g.Object; use Java.L a n g.Object; package Foo is type Typ (Self : access Obj e c t .TypÕClass) is new abstract Obj e c t .T y p with null record; pragma Java_Interface ( T y p) ; type Ref is access all Typ'Class; procedure Proc (This : access Typ; Val : Float) function F u n c (This : access Typ) return Float end F o o ; X : Bar := new Bar.Typ; Y : F o o.Ref := X.I_Foo; -- OK -conversion allowed, no checks. Z : Bar.Ref := Foo.Ref (Y.Self); -- At run-time, check that -- Y points to an object in Bar.Obj'Class Java_Constructor public class C { public int field; public C () { field = 3; } public C (i n t i) { field = i; } public C (int I, int j ) { this (I + j); } } with Java.Lang.Object; package C is type Typ T y p is new Java.Lang.Object.Typ with record Field : Integer; end record; type Ref is access all Typ'Class; function n e w _ C (This : Ref := null) return Ref; function n e w _ C (I : Integer; This : Ref := null) return Ref; function n e w _ C (I, J : Integer; This : Ref := null) return Ref; pragma Java_Constructor (new_C); end C; package body C i s function new_C (This : Ref := null) return Ref is Super : Java.L a n g.Object.Ref := new_Object (Object.Ref (This)); begin This.Field := 3; return This; end new_C; function new_C (I : Integer; This : Ref := null) return Ref is Super : Java.L a n g.Object.Ref := new_Object (Object.Ref (This)); begin This.Field := I; return This; end new_C; function new_C (I, J : Integer; This : Ref := null) return Ref is Ignore : Ref := new_C (I + J, Object.Ref (This)); begin return This; end new_C; java.lang.Object with type Java.L a n g.String.Ref is access; package J a v a .L a n g. O b j e c t is type T y p is tagged limited private ; type R e f is access all TypÕClass; É private type T y p is tagged limited null record; end Java.Lang.Object; type T y p is tagged lim i t e d private; 4Java classes are limited types Ð no object assignment (no deep cop y ) 4Warning: Ð must call a constructor to create an object (Java semantics) Ð No stand alone Java object can be created on the Ada side if there is no default constructor that the compiler can c a l l Problem if no default constructor public class Bar { public Bar (int i) {É} É } // only constructor O b j : Bar.Typ; -- ? ? ? JGNAT: Walk through a simple demo applet Overview Java Applets vs Applications Creating a new applet with JGNAT Compiling and running the Applet Applet vs Application 4ÒWrite once, execute anywhereÓ 4Executed by a JVM interpreter 4Applet: Embedded in a Web browser. Ð Security restrictions 4Application: Independent program Ð Full access to the Java API Applets (1) 4Extends the java.applet.Applet class Called by the browser to this HTML applet thatdocument it has 4Embeddedinform in an Called by theinto browser to been loaded the through the <Applet> tag. inform this applet that ittoshould Called by the browser system. start its execution. inform this applet that it should 4Four special methods: Called by the browser when stop its execution. the applet is being reclaimed Ð Init and should destroy any Ð Start resources that it has allocated Ð Stop Ð Destroy Applets (2) 4Security restrictions: Ð No access to the file system on the client Ð No access to serial or parallel ports Ð And others... 4Full access to GUI Getting documentation 4Full online documentation to the Java API 4Documentation always up-to-date through javadoc : classes hierarchy, fields, methods,etc... Writing a Java applet Creating a new type ÒExtendsÓ the Applet class inherits 4The new type must inheritand from theits java.applet.Applet class Set the Java primitive convention sooperations that with Java.Applet.Applet; are package Tictactoesubprograms is with the with t y p e Typ is new compatible Java.Applet.Applet.Typ inherited Java API record É end record; pragma Convention (Java, Typ); end Tictactoe; Writing a Java applet Adding fields (1) 4Creating Record components Ð Mapped to object fields of the Java class type Typ is new É with record First : Boolean; Is_New_Game: Boolean; NotImage : Java.Awt.Image.Ref; CrossImage : Java.Awt.Image.Ref; end record; Writing a Java applet Adding fields (2) 4Global variables Ð Mapped to ÒstaticÓ Java fields package Tictactoe is É White : aliased Position; Black : aliased Position; OK : constant Integer := 0; Win : constant Integer := 1; ... end Tictactoe; Writing a Java applet Writing new subprograms (1) 4Creating new primitive subprograms function Your_Move (Board : access Typ; M : Square) Has to be a primitive return Boolean; operation of Typ in (could Name visible the useJVM. ÒinÓ Used or Òinwhen outÓ parameters) interfacing to Java 4Specifying a specific external name pragma Export (Java, Your_Move, ÒyourMoveÓ); Writing a Java applet Writing new subprograms (2) 4Creating non-primitive subprograms Ð Mapped to ÒstaticÓ Java functions type Position is array (0 .. 8) of Boolean; function Is_A_Winner (Pos : access Position) return Boolean; Writing a Java applet Overriding inherited subprograms 4Must have the same prototype as in the Java API procedure Paint (This : access Typ; G1 : access Graphics.Typ'Class); procedure Init (This : access Typ); Called to initialize the Special function called applet every time the applet needs to be redrawn Writing a Java applet Implementing an interface (1) 4Reacting to events requires implementing the relevant Java interface Ð The subprograms will be called automatically by the JVM on each event (mouse, keyboard): mousePressed, mouseReleased, etc... Writing a Java applet Implementing an interface (2) 4Interfaces are declared by applying pragma Java_Interface to an abstract used The typeDiscriminant must be type abstract,for asconversion well as the subprograms package Java.Awt.Event.MouseListener is type Typ (Self : access Object.Typ'Class) is abstract new Java.Lang.Object.Typ with Declares the type as record a Java interface É end record; pragma Java_Interface ( T y p) ; end MouseListener; Writing a Java applet Implementing an interface (3) One discriminant 4Interfaces per areinterface, implemented used for conversions access discriminants using type Typ (I_ImageObserver : access ImageObserver.Typ'Class; I_MouseListener : access Mouselistener.Typ'Class) is new Java.Applet.Applet.Typ (I_ImageObserver) with record É end record; Writing a Java applet Implementing an interface (4) 4Interface subprograms must be overridden procedure mouseReleased (This : access Typ; E : access MouseEvent.Typ'Class); pragma Convention (Java, MouseReleased); 4pragma Convention currently needed so that the compiler can generate the call properly Writing a Java applet Interfacing to Java functions (1) 4Create a public static Java function public class support { static public String convert (byte s []) { return new String (s); }} 4This function will be implemented as an intrinsic operator (Ò+Ó) Writing a Java applet Interfacing to Java functions (2) 4Create an Ada spec for this Java function package Support is function Convert (S : String) return String.Ref; private pragma Import (Java, Convert, "convert"); end Support; pragma Import (Java, Support, "support"); Compiling the Applet 4jvm2ada generates the Ada specs for the Java API classes 4jgnatmake: recompiles each package needed by your applet Ð Creates a set of Java class files Ð Invokes jgnatbind to generate the elaboration code Running the Applet (1) 4Create a HTML document containing an <applet> Tag <applet CODEBASE=Ò.Ó CODE=Òtictactoe$typ.classÓ WIDTH=200 HEIGHT=200> Sorry, can't show the applet</applet> 4All classes must be in the same directory Running the Applet (2) 4Appletviewer 4Web Browser Ð Netscape Ð Internet Explorer Ð HotJava Ð etc... Conclusion 4Most details can be ignored when not interfacing the Java API 4Multi-threading supported 4Ada library not completely supported yet, but a good part of it is available (Text_IO, etcÉ) GNAT: Complete Ada Solution 100% Java compatible