Agenda Développement par délégation 6- Compléments illustrés en JAVA Thierry DESPRATS Rappel et limites de l’approche par héritage Approche par délégation Exemple Type générique, Meta-Type Le type Any Le type TypeCode Exemple Gestion dynamique de valeurs d’any Mode d’invocation dynamique Université Paul SABATIER – Toulouse III IRIT- SIERA http://www.irit.fr/~Thierry.Desprats [email protected] Référentiel d’Interfaces (IR) Composition dynamique de requêtes Invocation dynamique et modalités Exemples Compléments CORBA © 2005-06 Th. Desprats Approche statique par délégation (1/7) Approche statique par délégation (2/7) Rappel approche par héritage Illustration du mode par héritage : Principe : org.omg.Portable.ObjectImpl La classe d’implémentation Java hérite du squelette de l’interface à implémenter public class EuroImpl extends _EuroPOA { Limites de l’approche par héritage en java: Pas d’héritage multiple en JAVA : impossible de réutiliser les classes d’implémentation (pas de répercussion des héritages IDL sur les implémentations JAVA) Impossibilité d’associer une seule classe d’implémentation JAVA à plusieurs interfaces CORBA Compléments CORBA © 2005-06 Th. Desprats 3 org.omg.Portable.Servant extends Stub _EuroStub.java implements Interface 2 extends Skeleton _EuroPOA.java implements Operations extends Servant EuroImpl.java Euro.java Compléments CORBA EuroOperations.java © 2005-06 Th. Desprats 4 1 Approche statique par délégation (3/7) Approche statique par délégation (4/7) Approche par délégation Illustration du mode par délégation : Principe : La classe d’implantation va concerner non plus l’interface IDL de l’objet, mais l’interface d’opérations de l’objet org.omg.Portable.ObjectImpl public class EuroImpl implements EuroOperations { Utilisation de la classe de délégation « tie » générée lors de la compilation IDL de l’interface Toto vers Java : TotoTie.java Il s’agit d’une implantation par défaut de l’interface à laquelle elle est associée qui va déléguer le travail des opérations et attributs vers une classe d’implantation quelconque Impacts sur le développement : Côté client : aucune modification Côté serveur : associer une instance de la classe de délégation à une instance d’une classe implémentant l’interface d’opérations requise EuroPOA.java extends _EuroStub.java Interface © 2005-06 Th. Desprats 5 EuroPOATie.java implements délégation Operations EuroImpl.java Euro.java Compléments CORBA extends Stub implements org.omg.Portable.Servant extends EuroOperations.java Compléments CORBA © 2005-06 Th. Desprats Approche statique par délégation (5/7) Approche statique par délégation (6/7) Extrait de EuroPOATie.java Ecriture du serveur ServeurConvertisseur.java : package Convertisseur; … public class EuroPOATie extends EuroPOA { private EuroOperations _tie; private org.omg.PortableServer.POA _poa; 3/ Incarnation de l’objet // Création d’une instance de la classe d’implémentation EuroImpl monEuro = new EuroImpl(); public EuroPOATie(EuroOperations tieObject) { _tie = tieObject; } public EuroPOATie(EuroOperations tieObject, org.omg.PortableServer.POA poa) { _tie = tieObject; _poa = poa; } public EuroOperations _delegate() { return _tie; public void _delegate(EuroOperations delegate_) { } _tie = delegate_; public org.omg.PortableServer.POA _default_POA() { if (_poa != null) return _poa; else return super._default_POA(); public double taux() { return _tie.taux(); public void taux(double value) … Compléments CORBA 6 } // Association EuroPOATie monEurotie = new EuroPOATie(moneuro); // Fabrication d’un Identifiant(OID) pour attribution par le POA byte[] monEuroId = args[0].getBytes(); // Activer le servant dans le POA et lui attribuer l'ID poa.activate_object_with_id(monEuroId, monEurotie); } // le POA dispose désormais de la référence } { _tie.taux(value); } © 2005-06 Th. Desprats 7 Compléments CORBA © 2005-06 Th. Desprats 8 2 Approche statique par délégation (7/7) Type générique, Meta-type (1/17) Illustration d’implantation unique Définition Contrat idl : Type IDL module Exemple { Type générique capable de contenir une valeur de n’importe quelle autre type CORBA (standard ou utilisateur). interface A { void f(); }; interface B(:A) { void g(); }; }; Utilisation Classe d’implantation unique : Public class AetBImpl implements [AOperations], BOperations { Comme type de paramètre, de retour d’opération, ou comme type de base d’un type construit public void f() { System.out.println(“il pleut“); }; public void g() { System.out.println(“il neige“); }; (exemple : type d’un membre d’une structure) }; Projection en JAVA Serveur : … Classes : org.omg.CORBA.Any org.omg.CORBA.AnyHolder AetBImpl toto new AetBImpl; ATie a_tie = new ATie(toto); BTie b_tie = new BTie(toto); … Compléments CORBA any © 2005-06 Th. Desprats 9 Compléments CORBA © 2005-06 Th. Desprats Type générique, Meta-type (2/17) Type générique, Meta-type (3/17) Création d’une variable any en Java : Illustration en Java : org.omg.CORBA.Any a = orb.create_any(); org.omg.CORBA.Any b = orb.create_any(); org.omg.CORBA.Any c = orb.create_any(); Méthode de org.omg.CORBA.orb : create_any() Exemple : // Affectation d’un chaîne a.insert_string(“Il fait beau“); // Création d’un Any : a ne contient aucune valeur org.omg.CORBA.Any a = orb.create_any(); // Affectation d’un entier b.insert_long(64); Insertion/Extraction de valeur : // Affectation d’une structure individu i = new individu(); i.nom = “Desprats”; i.prenom = “Thierry”; i.adresse = “Rue Corba”; individuHelper.insert(c,i); Valeur d’un type primitif toto : Insertion : insert_toto(valeur) Extraction : extract_toto() Valeur d’un type construit toto : // Récupération des valeurs String s = extract_string(a); long t = extract_long(b); individu j = individuHelper.extract(c); Insertion : totoHelper.insert(any, valeur) Extraction : totoHelper.extract(any) Compléments CORBA 10 © 2005-06 Th. Desprats 11 Compléments CORBA © 2005-06 Th. Desprats 12 3 Type générique, Meta-type (4/17) Type générique, Meta-type (5/17) Le Meta-type TypeCode : Le type énuméré TCKind : Type IDL TypeCode Type IDL TCKind En Java : org.omg.CORBA.TypeCode Objectif : donner les moyens de description de tout type CORBA : En Java : org.omg.CORBA.TCKind Objectif : énumérer les genres de types CORBA : = = > tout type IDL (standards et utilisateurs) est associé à un TypeCode La nature des informations d’un TypeCode dépend du type qu’il décrit : = = > Les types sont classés par « genres » appelés TCKind Compléments CORBA © 2005-06 Th. Desprats 13 // Définition du type TCKind Enum TCKind { tk_null, tk_void, tk_short, tk_long, tk_ushort, tk_ulong, tk_float, tk_double, tk_boolean, tk_char, tk_octet, tk_any, tk_TypeCode, tk_Principal, tk_objref, tk_struct, tk_union, tk_enum, tk_string, tk_sequence, tk_array, tk_alias, tk_except, tk_longlong, tk_fixed, tk_value, tk_value_box tk_native, tk_abstract_interface }; Compléments CORBA © 2005-06 Th. Desprats Type générique, Meta-type (6/17) Type générique, Meta-type (7/17) Obtention d’un TypeCode : Utilisation d’un TypeCode (1/3): Méthodes de org.omg.CORBA.TypeCode : Pour un type primitif toto : Connaître le genre d’un type : Méthode de org.omg.CORBA.orb : get_primitive_tc(tcKind du type toto) kind() retourne un TCKind Connaître le nom d’un type non primitif : Exemple : // Récupération du type code associé à long org.omg.CORBA.TypeCode tc = orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_long); name() retourne un string Connaître le « Repository ID » d’un type non primitif : id() retourne un identifiant de la forme : [ IDL:] [préfixe] [chemin] [version] exemple : Pour un type construit toto : module Exemple { struct individu {string nom; string prenom; string adresse;}; interface A { void f();}; }; Méthode de totoHelper : type() Exemple : On obtient les repository IDs suivants : pour le module Exemple : pour l’interface A : pour le type individu : // Récupération du type code associé à la structure Individu org.omg.CORBA.TypeCode tc = individuHelper.type(); Compléments CORBA 14 © 2005-06 Th. Desprats 15 Compléments CORBA IDL:Exemple:1.0 IDL:Exemple/A:1.0 IDL:Exemple/individu/:1.0 © 2005-06 Th. Desprats 16 4 Type générique, Meta-type (8/17) Type générique, Meta-type (9/17) Utilisation d’un TypeCode (2/3): Utilisation d’un TypeCode (3/3): Connaître le type de référence d’un alias : Connaître les membres d’un type composé : (structures, unions, énumérations, exceptions, value types) member_count() retourne le nombre de membres présents dans le type member_name() retourne le nom du type dont l’index est précisé member_type() retourne le type code du membre dont l’index est précisé Exemple : à partir de cette description : Content_type() retourne un TypeCode Connaître le type de référence d’un tableau : Content_type() retourne un TypeCode Connaître la taille d’un tableau : length() retourne la taille struct individu {string nom; string prenom; string adresse;}; qu’afficherait à l’écran le code suivant ? org.omg.CORBA.TypeCode tc = individuHelper.type(); if (tc.kind().value() = = org.omg.CORBA.TCKind._tk_struct) { System.out.println(“Nom de la structure: “+tc.name()); System.out.println(“ID de la structure: “+tc.id()); System.out.println(“Nombre de membres : “+tc.member_count()); for( int i=0; i<tc.member_count(); i++) { System.out.println(“Nom du membre : “+tc.member_name(i)); System.out.println(“Type du membre : “+tc.member_type(i)); }} Compléments CORBA © 2005-06 Th. Desprats 17 Comparer des TypeCodes : equal() retourne un booléen (égalité stricte) equivalent() retourne un booléen (égalité indirecte) Connaître le type d’une valeur Any : type() retourne le TypeCode de la valeur contenue dans un any Compléments CORBA © 2005-06 Th. Desprats Type générique, Meta-type (10/17) Type générique, Meta-type (11/17) Exemple: Exemple Interface polymorphe : typedef sequence <long> longSeq struct individu {string nom; string prenom; string adresse;}; exception TypeInconnu { }; interface Polymorphe { void pass(in any valeur) raises TypeInconnu); }; Servant Java : public class PolymorpheImpl extends PolymorphePOA { public void pass(org.omg.CORBA.Any val) throws TypeInconnu { org.omg.CORBA.TypeCode tc = valeur.type(); switch (getEquivalentKind(tc)) { case org.omg.CORBA.TCKind_tk_long : int l = valeur.extract_long(); System.out.println(“recu un entier de valeur: “+l); break; case org.omg.CORBA.TCKind_tk_string : String s = valeur.extract_string(); System.out.println(“recu une string de valeur: “+s); break; Compléments CORBA © 2005-06 Th. Desprats 19 : 18 Servant Java case org.omg.CORBA.TCKind_tk_string : String s = valeur.extract_string(); System.out.println(“recu une string de valeur: “+s); break; case org.omg.CORBA.TCKind_tk_struct : if (tc.equal(individuHelper.type())) { individu i = individuHelper.extract(valeur); System.out.println(“recu un individu : “+i.nom+” “ +i.prenom”+” “+i.adresse); } else throw new TypeInconnu(); break; case org.omg.CORBA.TCKind_tk_sequence : if (tc.equal(longSeqHelper.type())) { int [] seq = longSeqHelper.extract(valeur); System.out.println(“recu une sequence d’entiers :”); for (int = i; i<seq.length; i++) System.out.println(“Elt n° “+i+“:”+seq[i]); } else throw new TypeInconnu(); break; default throw new TypeInconnu(); } } Compléments CORBA © 2005-06 Th. Desprats 20 5 Type générique, Meta-type (12/17) Type générique, Meta-type (13/17) Exemple : Exemple : Client Servant Java Private int getEquivalentKind(org.omg.CORBA.TypeCode tc) { switch (tc.kind().value() { case org.omg.CORBA.TCKind_tk_alias : try { return tc.content_type().kind().value(); } catch (org.omg.CORBA.TypeCodePackage.BadKind ex) { } return org.omg.CORBA.TCKind._tk_null; default : return tc.kind().value(); } } } Serveur : classique ... PolymorpheImpl poly = new PolymorpheImpl(); ... Compléments CORBA © 2005-06 Th. Desprats 21 ... try { Polymorphe poly = //IOR récupéré aupès du NS org.omg.CORBA.Any a = orb.create_any(); a.insert_long(1515); poly.pass(a); a.insert_string(“Marignan”); poly.pass(a); individu i = new individu (“Francois”, “Premier”, “Chambord”); individuHelper.insert(a,i); poly.pass(a); int[] seq = new int[8]; for(int i = 0; i<seq.length; i++) seq[i] = i; longSeqHelper.insert(a,seq); poly.pass(a); a.insert_float((float)3.14); poly.pass(a); } catch (TypeInconnu ex) { System.out.println(“serveur a recu type inconnu :”); } ... Compléments CORBA © 2005-06 Th. Desprats Type générique, Meta-type (14/17) Type générique, Meta-type (15/17) Création de Type codes (1/3) Création de Type codes (2/3) Intérêt : dans un mode d’invocation dynamique on ne dispose pas des classes Helper ! (pas de génération IDL vers Java) = = > être capable de créer ses propres type codes qui sont indispensables à l’emploi du type Any requis dans les mécanismes dynamiques Classe Orb.omg.CORBA.Orb fournit des opérations pour chaque type descriptible en IDL Les autres types : Types primitifs : Inutile d’en créer un (ils l’ont déjà) Récupération par : get_primitive_tc(in TcKind kind) Compléments CORBA © 2005-06 Th. Desprats 23 22 create_string_tc(in unsigned long bound) create_wstring_tc(in unsigned long bound) create_enum_tc(in RepositoryID id, in Identifier Name, in EnumMemberSeq members) create_struct_tc(in RepositoryID id, in Identifier Name, in StructMemberSeq members) create_exception_tc(in RepositoryID id, in Identifier Name, in StructMemberSeq members) create_interface_tc(in RepositoryID id, in Identifier Name) create_sequence_tc(in unsigned long bound, in TypeCode element_type) create_array_tc(in unsigned long bound, in TypeCode element_type) create_alias_tc(in RepositoryID id, in Identifier Name, in TypeCode original_type) … Compléments CORBA © 2005-06 Th. Desprats 24 6 Type générique, Meta-type (16/17) Type générique, Meta-type (17/17) Création de Type codes (3/3) Gestion dynamique de valeurs Any Exemple : struct individu {string nom; string prenom; string adresse;}; Code construisant le Type code correspondant : org.omg.CORBA.StructMember [] members = new org.omg.CORBA.StructMember[3]; members[0] = new org.omg.CORBA.StructMember(); members[0].name = “nom“; members[0].type = orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_string); members[1] = new org.omg.CORBA.StructMember(); members[1].name = “prenom“; members[1].type = orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_string); members[2] = new org.omg.CORBA.StructMember(); members[2].name = “adresse“; members[2].type = orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_string); Org.omg.CORBA.TypeCode tc = orb.create_struct_tc(“IDL:Exemple/individu:1.0”,”individu”, members); Compléments CORBA © 2005-06 Th. Desprats 25 Problème : extraction et insertion de valeurs Any pour les types non primitifs lorsqu’on ne dispose pas des Helper (contexte dynamique) Solution : mécanisme de gestion dynamique de ces valeurs Interfaces héritant de DynAny : DynEnum, DynStruct, DynUnion, DynSequence, DynArray, DunValue Classes org.omg.DynamicAny Permettent de créer une valeur correspondant à un type de données puis générer un Any qui contiendra cette valeur et inversément ce qui permettra de manipuler une valeur contenue dans un Any. Compléments CORBA © 2005-06 Th. Desprats Invocation dynamique (1/7) Invocation dynamique (2/7) Référentiel d’interfaces (1/3) Référentiel d’interfaces (2/3) Objectifs de l’IR : Les relations entre interfaces de l’IR : Opérations pour chaque interface Recherche, création Récupération de descriptions, de Repository ID, de type code (sous forme canonique ou non) 26 répertorier les descriptions IDL des objets CORBA fournir un ensemble d’interfaces pour obtenir des informations sur la description d’un type Accès par la référence initiale InterfaceRepository Organisation : chaque type IDL est associé à une interface du référentiel Compléments CORBA © 2005-06 Th. Desprats 27 Compléments CORBA © 2005-06 Th. Desprats 28 7 Invocation dynamique (3/7) Invocation dynamique (4/7) Référentiel d’interfaces (3/3) Création dynamique de requête Exemple de l’interface OperationDef : Interface DII (Dynamic Invocation Interface) Classe org.omg.CORBA.Object propose plusieurs méthodes pour créer des requêtes vers l’objet qu’elle référence Deux méthodes : enum OperationMode {OP_NORMAL, OP_ONEWAY }; enum ParameterMode {PARAM_IN, PARAM-OUT, PARAM_INOUT }; struct ParameterDescription { Identifier name; TypeCode type; IDLType type_def; ParameterMode mode; }; typedef sequence<ParameterDescription> ParDescriptionSeq; typedef Identifier ContextIdentifier; typedef sequence<ContextIdentifier> ContextIdSeq; typedef sequence<ExceptionDef> ExceptionDefSeq; typedef sequence<ExceptionDescription> ExcDescriptionSeq; struct OperationDescription { Identifier name; RepositoryID id; … TypeCode result; OperationMode mode ContextIdSeq contexts; PardescriptionSeq parameters; ExcDescriptionSeq exceptions; }; interface Operationdef : Contained { … readonly attribute TypeCode result; attribute ParDescriptionSeq params; attribute OperationMode mode; OperationDescription describe(); … Compléments CORBA © 2005-06 Th. Desprats 29 Compléments CORBA Invocation dynamique (5/7) Invocation dynamique (6/7) invoke appel bloquant send_oneway appel asynchrone (oneway) send_deferred appel non bloquant poll_response teste la présence de la réponse get_response récupère la réponse Méthodes de la classe org.omg.CORBA.ORB send_multiple_request_oneway(Request[]) envoi +sieurs requêtes oneway send_multiple_request_deferred envoi non bloquant poll_next_response teste la présence d’une réponse get_next_response récupère une réponse © 2005-06 Th. Desprats Créer une requête simple précisant uniquement le nom de l’opération à invoquer puis opérations pour rajouter successivement paramètres, retour, exception, contexte… Créer en un seul appel une requête complète : Méthode à deux formes : orb.omg.CORBA.Request _create_request ( org.omg.CORBA.Context ctx, String operation, org.omg.CORBA.NVList arg_list, org.omg.CORBA.NamedValue result, [ org.omg.CORBA.ExceptionList exlist, org.omg.CORBA.ContextList ctxlist, ] ); © 2005-06 Th. Desprats 30 org.omg.CORBA.Object obj = // récupération de l’IOR de l’Objet cible Sémantiques d’invocation possibles : Méthodes de la classe org.omg.CORBA.Request Compléments CORBA Exemple : Invocation dynamique de requête 31 // préparation des paramètres org.omg.CORBA.NVList param_list = orb.create_list(0); org.omg.CORBA.Any param1 = orb_create_any(); org.omg.CORBA.Any param2 = orb_create_any(); param_list.add_value(“”, param1, org.omg.CORBA.ARG_IN.value); param_list.add_value(“”, param2, org.omg.CORBA.ARG_IN.value); param1.insert_float((float) 3.14); param2.insert_float(5); // préparation du type de retour org.omg.CORBA.Any ret_value = orb_create_any(); org.omg.CORBA.NamedValue retour = orb.create_named_value(“”, ret_value,0); ret_value.type(orb.get_primitive_tc(org.omg.CORBA.TCKind.tk_float)); // puis de la liste des exceptions org.omg.CORBA.StructMember [] members = new org.omg.CORBA.StructMember[0]; org.omg.CORBA.TypeCode tc_exception = orb.create_exception_tc(“IDL:ObjectCible/DivisionParZero:1.0”, “DivisionParZero“, members); org.omg.CORBA.ExceptionList exceptions = orb.create_exception_list(); Compléments CORBA © 2005-06 Th. Desprats 32 8 Invocation dynamique (7/7) Exemple : // et enfin du contexte org.omg.CORBA.ContextList cl = orb_create_context_list(); org.omg.CORBA.Context c = orb.get_default_context(); // Création de la requête à partir des préparations précédentes Org.omg.CORBA.Request req = obj._create_request(c,”division”,param_list,retour,exceptions,cl); //Invocation de l’opération req.invoke(); // Récupération éventuelle d’une exception java.lang.Exception exception = req.env().exception(); if (exception != null) { if exception instanceof org.omg.CORBA.UnknownUserException) System.out.println(”une Division par zero s’est produite”); else throw (org.omg.CORBA.SystemException) except; } // sinon on extrait le résultat float res= ret_value.extract_float(); System.out.println(“Resultat de la division :”+res); Compléments CORBA © 2005-06 Th. Desprats 33 9