Cours D cadre pour les langues pour la programmation distribuée en PDF


Télécharger Cours D cadre pour les langues pour la programmation distribuée en PDF

★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Télécharger aussi :


Cours D cadre pour les langues pour la programmation distribuée

...

Chapitre 1 Introduction

Avec les progrès de la technologie matérielle et de la communication, la concurrence et la distribution sont naturellement venues dans un large éventail d'applications, car elles tentent de faire face à un monde où les personnes et les informations sont géographiquement distribuées et où plusieurs choses peuvent se produire simultanément. La concurrence et la distribution introduisent un ensemble de problèmes qui augmentent considérablement la complexité du logiciel.

Tout d'abord, et surtout, les systèmes concurrents et distribués sont intrinsèquement plus complexes que les systèmes non distribués. Par «intrinsèquement», je veux dire que, indépendamment de toute réalisation de logiciel particulière, la modélisation de situations impliquant plusieurs composants actifs et simultanés qui peuvent communiquer entre eux est plus difficile que la modélisation de systèmes séquentiels et centralisés. .

Deuxièmement, les modèles de programmation existants et les langages qui sont appropriés pour des systèmes séquentiels, centralisés ne fournissent pas nécessairement les mécanismes appropriés pour exprimer efficacement des scénarios simultanés et distribués. En conséquence, la complexité inhérente à ces systèmes est fortement amplifiée dans les textes de programme eux-mêmes.

Lors du développement d'une application distribuée, et en plus des préoccupations fonctionnelles des applications (c.-à-d. Les fonctionnalités disponibles), les concepteurs et les programmeurs doivent gérer les problèmes de partition des composants à travers le réseau, les faire communiquer de manière appropriée, définir et synchroniser les activités simultanées, gérer les défaillances partielles et fournir des performances acceptables. Étant intrinsèques aux systèmes distribués, ces autres problèmes ne peuvent être ignorés; ils ne doivent pas seulement être pensés dans la conception, mais ils doivent finalement être traités dans le programme qui fonctionne dans le réseau des ordinateurs. Alors que très peu peut être fait pour diminuer la complexité naturelle des applications distribuées, il existe un espace pour améliorer la qualité et la fiabilité des processus de développement et de maintenance des programmes correspondants.

Cette thèse s'appuie sur les problèmes d'ingénierie logicielle impliqués dans la fusion des isba de distribution avec la fonctionnalité pour obtenir le comportement distribué souhaité. En particulier, il se penche sur le rôle des langages de programmation en tant qu'outils pour la programmation des problèmes de distribution.

1.1. Le problème

La figure 1 capture le problème de l'enchevêtrement de code qui est à la base de cette thèse. Sur la gauche, il y a le code d'une classe lorsqu'elle est utilisée dans un environnement non distribué. Sur la droite, il y a la "même" classe avec des capacités pour gérer les invocations simultanées et à distance. La première observation est que le code sur la droite est beaucoup plus grand. Ce n'est pas surprenant, étant donné qu'un scénario distribué est intrinsèquement plus complexe qu'un schéma non distribué. Cependant, après une analyse minutieuse du code de droite, nous arrivons à la conclusion qu'un tel code (1) a perdu l'encapsulation fonctionnelle de la version non distribuée, (2) est un entremêlement confus de lignes de code à des fins différentes, et (3) est plein d'informations redondantes.

Les langages de programmation existants, en particulier les langages orientés objet, ont des capacités relativement puissantes pour capturer la fonctionnalité des composants de l'application. Cependant, les langages de programmation existants, y compris les langages orientés objet, ont des capacités relativement médiocres pour capturer le comportement des composants lorsqu'ils sont distribués sur un réseau et lorsque la modularité de leur comportement séquentiel est coupée par l'exécution simultanée de leurs services.

Programmation simultanée et la distribution affecte la mise en œuvre de chacun des composants de manière à avoir tendance à traverser la fonctionnalité de ces composants. Cela peut également affecter la mise en œuvre de groupes de composants. Une simple division composant / interface du monde mène à des programmes qui sont une confusion embrouillante de lignes de code à des fins différentes.

1.2. L'approche

L'approche retenue dans cette thèse est de diviser le nœud des exigences et des contraintes des systèmes distribués en un certain nombre de préoccupations générales, chacune ayant sa propre cohérence et pouvant être considérée isolément tout au long du cycle de vie des applications. Cette séparation est préservée sur les textes de programme eux-mêmes, ce qui aboutit à des programmes qui ne sont pas mélangés.

Pour cela, un cadre appelé D a été conçu. D est un cadre de langage qui prend en charge de nouveaux types de modules pour résoudre certains problèmes de distribution difficiles à capturer en classe. Ces nouveaux types de modules composent avec les classes de manière spéciale. La version de Dā € ™ de l'exemple de la figure 1 est montrée sur la figure 2: la classe est libre de code pour traiter les problèmes de distribution, et ceux-ci sont localisés dans des modules spéciaux.

Dans la conception de D, il était nécessaire d'identifier les préoccupations qui sont raisonnablement bien traitées dans les mécanismes de définition du langage de programmation existant, et les préoccupations qui ne le sont pas. Pour se référer à la première nous utilisons le terme composants; à ce dernier, nous avons donné le terme technique d'aspects [37]. Les aspects affectent le comportement distribué et simultané des composants, et sont donc étroitement liés à leur implémentation. Pourtant, ils ont des caractéristiques importantes qui 1) rendent souhaitable de les considérer séparément; 2) rend difficile la localisation de leurs effets sur l'un des composants; et 3) permet d'obtenir une séparation raisonnablement efficace des composants.

Sélection d'une classe représentative de systèmes distribués

"Système distribué" est un terme qui s'applique à un large éventail de systèmes qui existent dans l'ensemble du spectre de l'informatique. Le cadre linguistique proposé ici se concentre uniquement sur un sous-ensemble d'applications qui semblent être relativement importantes pour l'industrie du logiciel, au moins au cours de la prochaine décennie. Exemples: applications sur Internet, le Web, applications d'entreprise telles que les gestionnaires de calendrier, les gestionnaires de réseau, les systèmes de gestion de documents (numérisation, stockage, édition et impression intégrées), les systèmes de gestion hospitalière, les applications frontales base de données, environnements multi-utilisateurs interactifs, et bien d'autres comme ceux-ci. Tout au long de cette dissertation, le terme «application distribuée» ou «système distribué» est utilisé pour désigner ce sous-ensemble d'applications.

1.3. La thèse

Cette thèse démontre que le code pour implémenter certains problèmes de distribution peut être démêlé du code de fonctionnalité en fournissant de nouveaux mécanismes d'abstraction et de composition spécifiquement conçus pour la programmation de ces problèmes de distribution. Les nouveaux mécanismes peuvent être facilement intégrés dans un langage orienté objet avec peu de modifications à ce langage et à un coût très faible en termes de performance. Les nouvelles interfaces d'aspect sont faciles à comprendre. D conduit à des programmes dont les modules sont plus ciblés et où la séparation des préoccupations est plus claire que si l'on utilisait des langages orientés objet traditionnels.

Afin de valider ces revendications, trois ensembles de résultats différents sont utilisés:

(1) des études de cas, qui servent de base pour faire une analyse quantitative du cadre en termes de lignes de code et de mesures pour mesurer l'emmêlement;

(2) les mesures de performance; et

(3) une étude préliminaire des utilisateurs, dans laquelle une implémentation de D a été donnée à quatre utilisateurs alpha.

1.4. Synopsis de la Dissertation

La figure 3 est la feuille de route de la dissertation. Les flèches indiquent la structure de l'argumentation dans la thèse. Le chapitre 2 définit la motivation de D en analysant les sources de complexité dans les programmes distribués. Le chapitre 3 décrit la conception du cadre D, donne une spécification détaillée de la sémantique des deux langages d'aspect et discute des décisions de conception ainsi qu'un certain nombre d'alternatives de conception. Ces spécifications ont été concrétisées dans un langage appelé DJ, qui utilise Java comme langage de composant. DJ utilise la syntaxe décrite dans l'Annexe A. Une introduction à DJ est donnée dans l'Annexe B. DJ a été implémenté par un pré-processeur, appelé Assez Weaver, qui produit des patterns spécifiques de code Java. Ces architectures d'implémentation du code Java en sortie sont la clé pour implémenter correctement la sémantique spécifiée de D, et elles sont décrites au chapitre 4. De telles architectures déterminent, dans une certaine mesure, la mise en œuvre de l'Aspect Weaver elle-même, présentée en Annexe C. établir également le support de bibliothèque nécessaire pour exécuter les programmes DJ; cette bibliothèque est donnée à l'annexe D. Le chapitre 5 valide les revendications et analyse le cadre linguistique proposé. Une partie de la validation provient des commentaires des utilisateurs alpha, présentés à l'annexe E. Enfin, le chapitre 6 conclut la dissertation.

 Chapitre 2 Code Tangling

 "L'un des principaux objectifs de la conception de tout langage contemporain est de soutenir les résultats de

À la fin des années 1960, une petite révolution a commencé avec l'intention de définir des styles de programmation et des constructions de langage de programmation pour produire des programmes bien organisés. Cette nouvelle vague a été appelée programmation structurée [16, 19], et elle est venue dans la séquence de la crise du logiciel qui a résulté de l'écriture de programmes relativement grands et complexes avec des langages de programmation de bas niveau. Au centre de ce débat se trouvaient les déclarations go to, et les constructions de niveau supérieur qui les élimineraient. Beaucoup de gens prétendaient que les boissons étaient nocives, et les programmes qui les utilisaient entraînaient généralement un "code spaghetti" qui était difficile à comprendre. et maintenir. Les conservateurs ont prétendu que les toâ € ™ s étaient plus efficaces que toutes les autres constructions de plus haut niveau, et ne devraient donc pas être éliminés des langues. Dans [38], Knuth a suggéré que les disques n'étaient pas la cause du "code spaghetti", le vrai problème était les manières non utilisées dans lesquelles les programmeurs ont utilisé leur.

Presque trente ans et quelques innovations plus tard, les to go font partie de l'histoire des langues de programmation. La nouvelle génération de langages de programmation fournit un certain nombre d'abstractions puissantes, telles que des procédures, des fonctions, des types de données récursifs, des classes et des objets, qui permettent le développement de systèmes logiciels si grands et complexes qu'ils ne pourraient probablement pas être écrits. , maintenu) avec les langues d'il y a trente ans. Au centre des technologies modernes de programmation est la notion de «composant fonctionnel», c'est-à-dire, une sous-partie d'un grand système qui fournit une certaine fonctionnalité qui est intuitivement attrayante, est plus ou moins indépendante des autres parties, et peut être composé avec d'autres parties par une certaine forme de «uses» relation. Les com¬ patiants sont bien capturés par les définitions de fonction, de procédure ou de classe; et ils composent bien par des appels de fonction / procédure, et des invocations de méthode.

Cependant, tout comme il y a trente ans, les applications repoussent les limites des technologies actuelles de tramage. Dans les systèmes logiciels d'aujourd'hui, de nombreuses questions qui doivent être programmées se rapportent à d'autres parties du système de manière sophistiquée que la relation "usesâ €" ne fait pas "¢ t tout à fait capturer dans leur intégralité. En conséquence, beaucoup d'informations utiles sont perdues lors de la programmation de ces problèmes avec les mécanismes de composition existants. Parce que ces problèmes doivent être programmés, ils finissent par être insérés dans le code componentsâ € ™ de manière plus ou moins arbitraire.

 Le résultat est une recette plus sophistiquée de code spaghetti, où, au lieu d'aller à l'écart du flux principal de contrôle dans un segment de code, les lignes de code de niveau relativement élevé distraient le flux principal de contrôle dans la mise en œuvre d'un composant. Ce phénomène a été appelé enchevêtrement de code [37]. Ce chapitre fournit une analyse détaillée de l'enchevêtrement de code dans les systèmes distribués, de son origine et de la façon dont il a été traité par les directives de programmation et les langages de programmation.

2.1. Comment les programmes s'embrouillent

Afin d'analyser le problème d'emmêlement de code, ce problème sera d'abord présenté avec un exemple illustratif. Supposons que nous voulons implémenter un localisateur de livre qui gère une association entre deux livres et leurs emplacements physiques au sein d'une entreprise. La fonctionnalité de tels objets se compose de trois services: (i) un service de registre qui prend un livre et un emplacement, et enregistre la paire dans une base de données interne; (ii) un service de désenregistrement qui prend un livre et l'élimine du registre; et (iii) un service de localisation qui prend une chaîne de clé, recherche dans les champs de chaîne des livres les correspondances possibles avec la clé, et retourne l'emplacement du premier livre qui lui correspond. Outre cette fonctionnalité de base, nous souhaitons que les localisateurs de livres soient accessibles depuis d'autres sites du réseau et qu'ils traitent les demandes simultanément.

Les trois sous-sections suivantes présentent une implémentation possible de cet exemple en utilisant Java. À ce stade, rien ne sera dit sur le rôle que le langage de programmation particulier et le style ont dans le développement de cette petite application; ce sera le sujet des prochaines sections.

2.1.1. Implémentation de la fonctionnalité

La figure 4 montre une implémentation possible des composants de base de cette petite application. Il se compose de trois classes, à savoir BookLocator, Book et Location. La classe BookLocator exécute trois méthodes qui correspondent aux services spécifiés; les classes Book et Location sont essentiellement des structures de données.

 classe publique BookLocator public class Livre {

{// implémentation possible de Livres

// Ceci est juste une implémentation possible. Titre de chaîne, auteur;

// les livres [i] sont dans des emplacements [i] int isbn;

livres de livres privés []; Propriétaire du projet

Emplacement privé []; Première page OCRImage;

int intbooks = 0;

// le constructeur public Book (String t, String a,

BookLocator public (int dbsize) {int n) {

livres = nouveau livre [dbsize]; title = t; auteur = a; isbn = n;



locations = nouvel emplacement [dbsize]; ]

] public String get_title () {

Registre public nul (Livre b, Lieu l) Renvoie le titre;

lance LocatorFull {]

public String get_author () {

if (nbooks> books.length) renvoie l'auteur;

lancer un nouveau LocatorFull (); ]

else {public int get_isbn () {

// Mettez-le simplement à la fin return isbn;

livres [nbooks] = b; ]

emplacements [nbooks ++] = l; ]

] public class Lieu {

] // Implémentation possible des emplacements

public void unregister (Livre b) {public int building, room;

Livre abook = livres [0]; int i = 0; Emplacement public (int bn, int rn) {

while (i

abook.get_isbn ()! = b.get_isbn ()) room = rn;

abook = livres [++ i]; ]

si (i == nbooks)]

revenir;

// déplace simplement le reste

tandis que (i

livres [i] = livres [i + 1];

emplacements [i] = emplacements [++ i];

]

--nbooks;

]

Emplacement public locate (String str)

jette BookNotFound {

Livre abook = livres [0];

int i = 0; booléen trouvé = faux;

while (i

if (abook.get_title (). compareTo (str) == 0 ||

abook.get_author (). compareTo (str) == 0)

trouvé = vrai;

sinon abook = livres [++ i];

]

si (trouvé == faux)

lancer un nouveau BookNotFound (str);

les lieux de retour [i];

]

]

Figure 4. Implantation simple de localisateurs de livres, de livres et de lieux.

2.1.2. Ajout de contraintes de synchronisation

La spécification stipule également que les localisateurs de livres devraient être en mesure de traiter plusieurs demandes de façon concurentielle. Après avoir écrit les classes en Java, la concurrence existe sous la forme de threads qui exécutent les objets sans aucune synchronisation par défaut. Étant donné que les trois méthodes de la classe BookLocator utilisent et mettent à jour les mêmes variables d'instance, un code supplémentaire est nécessaire afin d'éviter les incohérences.

En ce qui concerne la simultanéité, les localisateurs de livres présentent un modèle assez commun: «lire» (dans ce cas, le service de localisation) peut être effectué simultanément tout en bloquant temporairement tous ¢ â € "writeâ € ¢ accès; Les accès «write» (dans ce cas, register et unregister) ne doivent pas être effectués simultanément et doivent bloquer tous les autres services.

Le code étendu est illustré à la Figure 5. Seule la classe BookLocator est affichée, car les deux autres classes restent inchangées. Le nouveau code de coordination est marqué en noir. Afin d'éviter de multiples accès conflictuels, il est nécessaire d'insérer des lignes de code à des points spécifiques de l'origi.

classe publique BookLocator {

livres de livres privés [];

Emplacement privé [];

int intbooks = 0;

protected int activeReaders = 0; protected int activeWriters = 0;

// le constructeur

BookLocator public (int dbsize) {

livres = nouveau livre [dbsize];

locations = nouvel emplacement [dbsize];

]

registre public nul (Livre b, Emplacement l)

lance LocatorFull {

beforeWrite ();

if (nbooks> books.length) {

afterWrite ();

lancer un nouveau LocatorFull ();

]

autre {

// Il suffit de le mettre à la fin

livres [nbooks] = b;

emplacements [nbooks ++] = l;

]

afterWrite ();

]

Annulation de l'annulation du registre public (Livre b) {

Livre abook = livres [0]; int i = 0;

beforeWrite ();

alors que (i

abook.get_isbn ()! = b.get_isbn ())

abook = livres [++ i];

si (i == nbooks) {

afterWrite ();

revenir;

]

// déplace simplement le reste

tandis que (i

livres [i] = livres [i + 1];

emplacements [i] = emplacements [++ i];

]

--nbooks;

afterWrite ();

]

// class BookLocator suite

Emplacement public locate (String str)

jette BookNotFound {

Livre abook = livres [0];

int i = 0; booléen trouvé = faux;

Emplacement l;

synchronized (this) {

while (activeWriters> 0) {

essayez {wait (); ]

catch (InterruptedException e) {]

]

++ activeReaders;

]

while (i

if (abook.get_title (). compareTo (str) == 0 ||

abook.get_author (). compareTo (str) == 0)

trouvé = vrai;

sinon abook = livres [++ i];

]

if (trouvé == faux) {

synchronized (this) {

--activeReaders; notifyAll ();

]

lancer un nouveau BookNotFound (str);

]

l = emplacements [i];

synchronized (this) {

--activeReaders; notifyAll ();

]

retour l;

]

void synchronisé protégé beforeWrite () {

while (ActiveReaders> 0 ||

activeWriters> 0) {

essayez {wait (); ]

catch (InterruptedException e) {]

]

++ activeWriters;

]

void synchronisé protégé afterWrite () {

--activeWriters; notifyAll ();

]

]

Figure 5. Coordination de l'accès simultané à la classe BookLocator.

 la mise en œuvre du composant final. Dans ce cas, nous devons (1) définir des variables d'instance supplémentaires; (2) effectuer un certain nombre de vérifications et affecter l'état de l'objet lors de la saisie des méthodes; et (3) changer l'état dans chaque point de sortie des méthodes. Ces bits de code à l'intérieur du corps des méthodes peuvent être des appels structurés à d'autres méthodes (par exemple dans beforeWrite et afterWrite) ou simplement un certain nombre d'instructions supplémentaires (comme, par exemple, dans la méthode locate). Une attention particulière doit être accordée aux méthodes qui renvoient des objets, car l'expression de retour peut affecter l'état de l'objet et doit donc également être protégée (voir la méthode locate).

Il convient de noter que le code de coordination particulier présenté à la figure 5 n'est qu'une des nombreuses possibilités de mise en œuvre de la coordination des accès simultanés. Un certain nombre de perfectionnements pourraient être effectués afin de minimiser les périodes de verrouillage, et un certain nombre d'autres styles de programmation auraient pu être utilisés. En bref, le programmeur disposait d'un degré de liberté relativement grand pour traduire les intentions de coordination en morceaux de code et les entrelacer dans la mise en œuvre de la compo- sition.

La complexité du programme est nécessairement plus élevée lorsque le problème de coordination est pris en compte. En outre, la stratégie de coordination particulière dépend, dans une certaine mesure, de la mise en œuvre du composant particulier. Cependant, en ayant à entrelacer manuellement la mise en œuvre de la coordination avec la mise en œuvre du composant, une grande partie de l'information de coordination, ainsi que la fonctionnalité de base du composant, est diluée. Ces deux préoccupations qui ont été initialement décrites séparément deviennent un seul bloc de code qui est difficile à comprendre et à raisonner.

2.1.3. Fourniture d'accès à distance

La dernière partie de la spécification est que les localisateurs de livres peuvent être consultés à partir d'autres sites dans le net. Supposons, par exemple, qu'ils font partie d'une application de gestion de documents beaucoup plus grande, et que la base de données de livres complète est gérée par un autre serveur (s). Afin d'accélérer les recherches, les localisateurs de livres devraient mettre en cache des informations sur les livres, à savoir leurs titres, auteurs et isbn.

La nouvelle version du code est illustrée à la Figure 6, où les nouveaux éléments de code sont marqués en noir. En général, le code de mise en œuvre de la distribution dépend fortement de la forme particulière utilisée et, contrairement au problème de la coordination, il n'y a même pas de compréhension commune de la meilleure façon de procéder. il. Dans ce cas, la fonction Java RMI [27] a été utilisée.

 Localisateur d'interface publique

extends rmi.Remote {

registre vide (BookI b, LocationI l)

lève rmi.RemoteException,

LocatorFull;

annuler l'annulation de l'inscription (BookI b)

Lance rmi.RemoteException;

EmplacementI localiser (BookI b)

lève rmi.RemoteException,

BookNotFound;

}

interface publique BookI

extends Serializable {

String get_title ();

Chaîne get_author ();

int get_isbn ();

}

interface publique LocationI

extends Serializable {

}



BookLocator de classe publique

extends UnicastRemoteObject

implémente Locator

{

livres de livres privés [];

Emplacement privé [];

int intbooks = 0;

protected int activeReaders = 0; protected int activeWriters = 0;

// le constructeur

BookLocator public (int dbsize) {

livres = nouveau livre [dbsize];

locations = nouvel emplacement [dbsize];

}

registre public nul (Livre b, Emplacement l)

lance LocatorFull {

beforeWrite ();

if (nbooks> books.length) {

afterWrite ();

lancer un nouveau LocatorFull ();

}

autre {

// Il suffit de le mettre à la fin

livres [nbooks] = b;

emplacements [nbooks ++] = l;

}

afterWrite ();

}

Annulation de l'annulation du registre public (Livre b) {

Livre abook = livres [0]; int i = 0;

beforeWrite ();

alors que (i

abook.get_isbn ()! = b.get_isbn ())

abook = livres [++ i];

si (i == nbooks) {

afterWrite ();

revenir;

}

// déplace simplement le reste

tandis que (i

livres [i] = livres [i + 1];

emplacements [i] = emplacements [++ i];

}

--nbooks;

afterWrite ();

}

 // class BookLocator suite

Emplacement public locate (String str)

jette BookNotFound {

Livre abook = livres [0];

int i = 0; booléen trouvé = faux;

Emplacement l;

synchronized (this) {

while (activeWriters> 0)

essayez {wait (); }

catch (InterruptedException e) {}

++ activeReaders;

}

while (i

if (abook.get_title (). compareTo (str) == 0 ||

abook.get_author (). compareTo (str) == 0)

trouvé = vrai;

sinon abook = livres [++ i];

}

if (trouvé == faux) {

synchronized (this) {

--activeReaders; notifyAll ();

}

lancer un nouveau BookNotFound (str);

}

l = emplacements [i];

synchronized (this) {

--activeReaders; notifyAll ();

}

retour l;

}

void synchronisé protégé beforeWrite () {

// comme avant

}

void synchronisé protégé afterWrite () {

// comme avant

}

}

classe publique Book implémente BookI {

// Implémentation possible de Livres

Titre de chaîne, auteur;

int isbn; Propriétaire du projet

Première page OCRImage;

Livre public (String t, String a, int n) {

title = t; auteur = a; isbn = n;

}

public String get_title () {Renvoie le titre; }

public String get_author () {eturn auteur;}

public int get_isbn () {return isbn; }

private write writeObject (ObjectOutputStream

s)

throws NotSerializableException, IOException {

s.writeObject (titre);

s.writeObject (auteur);

s.writeInt (isbn);

}

private void readObject (ObjectInputStream

s)

throws NotSerializableException, IOException {

title = (Chaîne) s.readObject ();

auteur = (Chaîne) s.readObject ();

isbn = s.readInt ();

}

}

La classe publique Location implémente LocationI {

// identique à la figure 4.

}

Figure 6. Fourniture d'un accès à distance aux localisateurs de livres.

Pour utiliser Java RMI, les classes doivent implémenter des interfaces qui étendent les interfaces Remote, Seriali1 ou Externalizable. Les instances de classes distantes ne sont jamais copiées sur des appels distants, tandis que les instances de classes sérialisables ou externalisables sont toujours transmises par copie sur des appels distants. Les classes qui implémentent l'interface Serializable peuvent redéfinir les méthodes writeObject et readObject pour personnaliser les stratégies de marshaling. C'est le cas pour la classe Book, où writeObject et readObject ne traitent que trois champs de la classe, évitant le marshaling du propriétaire et firstPage.

Un client du service de recherche de livre peut l'appeler de n'importe où dans le réseau, de la façon suivante:

// Récupère la référence au localisateur de livre,

// par exemple, à partir du serveur de noms

Locator BL = (localisateur) Naming.lookup ("// localhost / BookLocator");

// ...

// invocation du service de registre

Emplacement aLoc = nouvel emplacement (35, 1631);

Book aBook = nouveau livre (new String ("Title 1"), new String ("Auteur A"), 33);

BL.register (aBook, aLoc);

// ...

// invocation du service de localisation

Emplacement theLoc;

Chaîne title2;

// ...

theLoc = BL.locate (titre2);

Lorsqu'une invocation se produit, par exemple BL.locate (title2), le système RMI prend soin de traduire la référence d'objet BL en une adresse réseau et d'exécuter un protocole de communication entre l'espace courant et l'espace où l'objet BL est réellement . Une partie du protocole se contente de transférer les paramètres de l'appel, et, pour cela, des upcalls sont faits aux méthodes writeOb¬ject et readObject des objets du paramètre Serializable.

Bien que simple pour les cas simples, la programmation avec RMI devient rapidement un exercice non trivial. Supposons que les livres soient également utilisés par un service qui gère des projets. Ce nouveau composant est incrémenté par le code de la figure 7. Seules l'interface et les classes correspondantes sont affichées; la classe Book fait référence à la mise en œuvre montrée dans les figures précédentes.

1 Il y a une collision malheureuse de la terminologie, à savoir le mot «sérialisable». Dans les systèmes concurrents, la sérialisation désigne généralement les objets qui n'autorisent pas la concurrence interne, c'est-à-dire qui gèrent une requête à la fois. Dans les systèmes distribués, la sérialisation a une signification complètement différente, à savoir le processus de marshaling et les objets unmarshaling dans / à partir des flux. L'utilisation de ce mot sera évitée, sauf si vous faites référence à l'interface de sérialisation de Java.

 interface publique PManager

extends rmi.Remote {

newBook ​​booléen (BookI b, PriceI p)

lève rmi.RemoteException,

ProjectNotFound;

// autres services ommitted

}

classe publique ProjectManager extends UnicastRemoteObject implémente Pmanager {projets ProjectList;

 public class Project implémente ProjectI {

ProjId projectId;

Gestionnaire de la personne;

Les travailleurs PersonList;

Budget bdgtCenter;

ComputerList ordinateurs;

Livres BookList;

boolean newBook ​​(Livre b, Prix p) {

if (bdgtCenter.approvePurchase (p)) {

books.append (b);

retourner vrai;

}

return false;

newBook ​​booléen public (Livre b, Prix p)}

lève rmi.RemoteException, ProjectNotFound // autres méthodes omises

{}

Projet prj = b.get_owner ();

if (! projects.contains (prj))

lancer ProjectNotFound;

retourner prj.newBook ​​(b, p);

}



53