Probablement,
Dans cet article, qui est de nature générale, nous essaierons d'examiner certaines des bases de l'architecture Eclipse en tant que plate-forme de création d'outils de développement intégrés et donnerons une première idée des composants Eclipse qui constituent le fondement de la technologie. plateforme pour le « nouveau Configurateur » 1C : Entreprise.
Introduction à l'architecture Eclipse
Examinons d'abord quelques aspects généraux de l'architecture Eclipse à l'aide de l'exemple
Tout d'abord, il convient de noter qu'Eclipse se caractérise par une stratification architecturale assez claire, avec la séparation des fonctionnalités indépendantes du langage des fonctionnalités conçues pour prendre en charge des langages de programmation spécifiques, et la séparation des composants « centraux » indépendants de l'interface utilisateur des composants associés. avec interface utilisateur prise en charge.
Ainsi, la plate-forme Eclipse définit une infrastructure commune indépendante du langage, et les outils de développement Java ajoutent un IDE Java complet à Eclipse. La plate-forme Eclipse et le JDT se composent de plusieurs composants, chacun appartenant soit à un « noyau » indépendant de l'interface utilisateur, soit à une couche d'interface utilisateur (Figure 1).
Riz. 1. Plateforme Eclipse et JDT
Listons les principaux composants de la plateforme Eclipse :
- Runtime — Définit l'infrastructure du plugin. Eclipse se caractérise par une architecture modulaire. Essentiellement, Eclipse est une collection de « points d'extension » et d'« extensions ».
- Espace de travail — Gère un ou plusieurs projets. Un projet se compose de dossiers et de fichiers mappés directement sur le système de fichiers.
- Boîte à outils de widgets standard (SWT) - Fournit des éléments d'interface utilisateur de base intégrés au système d'exploitation.
- JFace — Fournit un certain nombre de frameworks d'interface utilisateur construits sur SWT.
- Workbench — Définit le paradigme de l'interface utilisateur Eclipse : éditeurs, vues, perspectives.
Il faut dire que la plateforme Eclipse fournit également de nombreux autres composants utiles pour créer des outils de développement intégrés, notamment Debug, Compare, Search et Team. Une mention spéciale doit être faite à JFace Text - la base pour créer des « éditeurs intelligents » de code source. Malheureusement, même un examen superficiel de ces composants, ainsi que des composants de la couche UI, n'est pas possible dans le cadre de cet article. Dans le reste de cette section, nous nous limiterons donc à un aperçu des principaux composants « centraux » de la plateforme Eclipse et JDT.
Runtime de base
L'infrastructure du plugin Eclipse est basée sur
Espace de travail principal
Presque tous les environnements de développement intégrés construits sur la plate-forme Eclipse fonctionnent avec l'espace de travail Eclipse. C'est l'espace de travail qui contient généralement le code source de l'application développée dans l'EDI. L'espace de travail correspond directement au système de fichiers et se compose de projets contenant des dossiers et des fichiers. Ces projets, dossiers et fichiers sont appelés les ressources espace de travail. L'implémentation de l'espace de travail dans Eclipse sert de cache par rapport au système de fichiers, ce qui permet d'accélérer considérablement la traversée de l'arborescence des ressources. De plus, Workspace fournit un certain nombre de services supplémentaires, notamment
Le composant Core Resources (plugin org.eclipse.core.resources) est responsable de la prise en charge de l'espace de travail et de ses ressources. En particulier, ce composant fournit un accès programmatique à l'espace de travail sous la forme modèles de ressources. Pour travailler efficacement avec ce modèle, les clients ont besoin d'un moyen simple de présenter un lien vers une ressource. Dans ce cas, il serait souhaitable de masquer à l'accès client l'objet qui stocke directement l'état de la ressource dans le modèle. Dans le cas contraire, dans le cas par exemple de la suppression d'un fichier, le client pourrait continuer à détenir un objet qui n'est plus dans le modèle, avec les problèmes qui en découlent. Eclipse résout ce problème en utilisant quelque chose appelé manipuler Ressource. Handle agit comme une clé (il ne connaît que le chemin d'accès à la ressource dans l'espace de travail) et contrôle complètement l'accès à l'objet de modèle interne, qui stocke directement les informations sur l'état de la ressource. Cette conception est une variation du modèle
Riz. La figure 2 illustre l'idiome Handle/Body tel qu'appliqué au modèle de ressource. L'interface IResource représente le handle d'une ressource et est une API, contrairement à la classe Resource, qui implémente cette interface, et à la classe ResourceInfo, qui représente le corps, qui ne sont pas des API. Nous soulignons que handle ne connaît que le chemin d'accès à la ressource par rapport à la racine de l'espace de travail et ne contient pas de lien vers les informations sur la ressource. Les objets d'information sur les ressources forment ce que l'on appelle une « arborescence d'éléments ». Cette structure de données est entièrement matérialisée en mémoire. Pour trouver l'instance d'informations sur la ressource correspondant à un handle, l'arborescence des éléments est parcourue en fonction du chemin stocké dans ce handle.
Riz. 2. IResource et ResourceInfo
Comme nous le verrons plus tard, la conception de base du modèle de ressource (nous pourrions l'appeler basée sur les handles) est également utilisée dans Eclipse pour d'autres modèles. Pour l’instant, énumérons quelques-unes des propriétés distinctives de cette conception :
- Handle est un objet de valeur. Les objets de valeur sont des objets immuables dont l'égalité n'est pas basée sur l'identité. De tels objets peuvent être utilisés en toute sécurité comme clé dans des conteneurs hachés. Plusieurs instances de handle peuvent référencer la même ressource. Pour les comparer, vous devez utiliser la méthode equals(Object).
- Handle définit le comportement d'une ressource, mais ne contient pas d'informations sur l'état de la ressource (les seules données qu'il stocke sont la "clé", le chemin d'accès à la ressource).
- Handle peut faire référence à une ressource qui n’existe pas (soit une ressource qui n’a pas encore été créée, soit une ressource qui a déjà été supprimée). L'existence d'une ressource peut être vérifiée à l'aide de la méthode IResource.exists().
- Certaines opérations peuvent être mises en œuvre uniquement sur la base des informations stockées dans le handle lui-même (opérations dites de handle-only). Les exemples sont IResource.getParent(), getFullPath(), etc. Il n’est pas nécessaire que la ressource existe pour qu’une telle opération réussisse. Les opérations qui nécessitent l’existence d’une ressource pour réussir lèvent une CoreException si la ressource n’existe pas.
Eclipse fournit un mécanisme efficace pour notifier les modifications des ressources de l'espace de travail (Figure 3). Les ressources peuvent changer soit à la suite d'actions effectuées dans l'EDI Eclipse lui-même, soit à la suite d'une synchronisation avec le système de fichiers. Dans les deux cas, les clients qui s'abonnent aux notifications reçoivent des informations détaillées sur les modifications sous la forme de « deltas de ressources ». Un delta décrit les changements entre deux états d'une (sous-)arborescence de ressources d'espace de travail et est lui-même une arborescence dont chaque nœud décrit une modification apportée à une ressource et contient une liste de deltas au niveau suivant qui décrivent les modifications apportées aux ressources enfants.
Riz. 3. IResourceChangeEvent et IResourceDelta
Le mécanisme de notification basé sur les deltas de ressources présente les caractéristiques suivantes :
- Un seul changement et plusieurs changements sont décrits en utilisant la même structure, puisque le delta est construit selon le principe de composition récursive. Les clients abonnés peuvent traiter les notifications de modification de ressources en utilisant une descente récursive à travers une arborescence de deltas.
- Le delta contient des informations complètes sur les modifications apportées à la ressource, y compris son mouvement et/ou les modifications des « marqueurs » qui lui sont associés (par exemple, les erreurs de compilation sont représentées sous forme de marqueurs).
- Étant donné que les références aux ressources sont effectuées via le handle, delta peut naturellement référencer une ressource distante.
Comme nous le verrons bientôt, les principaux composants de la conception du mécanisme de notification de changement de modèle de ressources sont également pertinents pour d'autres modèles basés sur des handles.
Noyau JDT
Le modèle de ressources de l'espace de travail Eclipse est un modèle fondamental indépendant du langage. Le composant JDT Core (plugin org.eclipse.jdt.core) fournit une API pour naviguer et analyser la structure de l'espace de travail d'un point de vue Java, ce que l'on appelle le « modèle Java » (Modèle Java). Cette API est définie en termes d'éléments Java, par opposition à l'API du modèle de ressources sous-jacente, qui est définie en termes de dossiers et de fichiers. Les principales interfaces de l'arborescence des éléments Java sont présentées dans la Fig. 4.
Riz. 4. Éléments du modèle Java
Le modèle Java utilise le même idiome handle/body que le modèle de ressource (Figure 5). IJavaElement est le handle et JavaElementInfo joue le rôle de corps. L'interface IJavaElement définit un protocole commun à tous les éléments Java. Certaines de ses méthodes sont uniquement de type handle : getElementName(), getParent(), etc. L'objet JavaElementInfo stocke l'état de l'élément correspondant : sa structure et ses attributs.
Riz. 5. IJavaElement et JavaElementInfo
Le modèle Java présente quelques différences dans l'implémentation de la conception de base du manche/corps par rapport au modèle de ressource. Comme indiqué ci-dessus, dans le modèle de ressources, l'arborescence des éléments, dont les nœuds sont des objets d'informations sur les ressources, est entièrement contenue en mémoire. Mais le modèle Java peut contenir un nombre d'éléments nettement plus important que l'arborescence des ressources, car il représente également la structure interne des fichiers .java et .class : types, champs et méthodes.
Pour éviter de matérialiser complètement l'intégralité de l'arborescence des éléments en mémoire, l'implémentation du modèle Java utilise un cache LRU d'informations sur les éléments de taille limitée, où la clé est le handle IJavaElement. Les objets d'information sur les éléments sont créés à la demande au fur et à mesure de la navigation dans l'arborescence des éléments. Dans ce cas, les éléments les moins fréquemment utilisés sont évincés du cache et la consommation mémoire du modèle reste limitée à la taille du cache spécifiée. Il s'agit d'un autre avantage de la conception basée sur les handles, qui masque complètement ces détails d'implémentation du code client.
Le mécanisme de notification des modifications apportées aux éléments Java est en général similaire au mécanisme de suivi des modifications apportées aux ressources de l'espace de travail évoqué ci-dessus. Un client souhaitant surveiller les modifications dans le modèle Java s'abonne aux notifications, qui sont représentées sous la forme d'un objet ElementChangedEvent contenant un IJavaElementDelta (Figure 6).
Riz. 6. ElementChangedEvent et IJavaElementDelta
Le modèle Java ne contient pas d'informations sur les corps de méthode ou la résolution de noms. Par conséquent, pour une analyse détaillée du code écrit en Java, JDT Core fournit un modèle supplémentaire (non basé sur des handles) :
Étant donné que les arbres de syntaxe peuvent consommer une quantité importante de mémoire, JDT ne met en cache qu'un seul AST pour l'éditeur actif. Contrairement au modèle Java, l'AST est généralement considéré comme un modèle « intermédiaire », « temporaire » dont les membres ne doivent pas être référencés par les clients en dehors du contexte de l'opération qui a conduit à la création de l'AST.
Les trois modèles répertoriés (modèle Java, AST, liaisons) forment ensemble la base pour créer des « outils de développement intelligents » dans JDT, y compris un puissant éditeur Java avec divers « assistants », diverses actions pour traiter le code source (y compris l'organisation d'une liste d'importation noms et mise en forme selon le style personnalisé), outils de recherche et de refactoring. Dans ce cas, le modèle Java joue un rôle particulier, puisque c'est lui qui sert de base à une représentation visuelle de la structure de l'application en cours de développement (par exemple, dans l'Explorateur de packages, Outline, Search, Call Hierarchy et Tapez Hiérarchie).
Composants Eclipse utilisés dans 1C:Enterprise Developments Tools
En figue. La figure 7 montre les composants Eclipse qui constituent la base de la plate-forme technologique pour 1C:Enterprise Development Tools.
Riz. 7. Eclipse en tant que plate-forme pour 1C : outils de développement d'entreprise
Plateforme Eclipse fournit une infrastructure de base. Nous avons examiné certains aspects de cette infrastructure dans la section précédente.
Comme tout outil véritablement généraliste, EMF convient à la résolution d'un large éventail de problèmes de modélisation, mais certaines classes de modèles (par exemple, les modèles basés sur des poignées évoqués ci-dessus) peuvent nécessiter des outils de modélisation plus spécialisés. Parler des champs électromagnétiques est une tâche ingrate, surtout dans les limites d'un seul article, puisqu'il s'agit du sujet d'un livre séparé, et plutôt épais. Notons seulement que le système de généralisations de haute qualité qui sous-tend l'EMF a permis la naissance de toute une gamme de projets dédiés à la modélisation, qui sont inclus dans le projet de haut niveau
1C:Enterprise Development Tools utilise activement à la fois EMF lui-même et un certain nombre d'autres projets de modélisation Eclipse. En particulier, Xtext est l'un des fondements des outils de développement pour les langages 1C:Enterprise tels que le langage de programmation et le langage de requête intégrés. Une autre base de ces outils de développement est le projet Eclipse Handly, dont nous parlerons plus en détail (des composants Eclipse répertoriés, il est encore le moins connu).
Les principes architecturaux de base des modèles basés sur des handles, tels que l'idiome handle/body, ont été abordés ci-dessus en utilisant le modèle de ressource et le modèle Java comme exemples. Il a également noté que le modèle de ressources et le modèle Java constituent des fondements importants pour les outils de développement Java (JDT) d'Eclipse. Et comme presque tous les projets *DT Eclipse ont une architecture similaire à JDT, il ne serait pas exagéré de dire que les modèles basés sur les handles sous-tendent de nombreux, sinon tous les IDE construits sur la plate-forme Eclipse. Par exemple, les outils de développement Eclipse C/C++ (CDT) disposent d'un modèle C/C++ basé sur des handles qui joue le même rôle dans l'architecture CDT que le modèle Java dans le JDT.
Avant Handly, Eclipse ne proposait pas de bibliothèques spécialisées pour la création de modèles de langage basés sur des handles. Les modèles qui existent actuellement ont été créés principalement en adaptant directement le code du modèle Java (aka copier/coller), dans les cas où cela permet Licence publique Eclipse (EPL). (Évidemment, ce n'est généralement pas un problème juridique pour, par exemple, les projets Eclipse eux-mêmes, mais pas pour les produits fermés.) En plus de son caractère aléatoire inhérent, cette technique introduit des problèmes bien connus : la duplication de code introduite par l'adaptation aux erreurs, etc. Le pire est que les modèles qui en résultent restent des « choses en soi » et ne tirent pas parti du potentiel d’unification. Mais isoler les concepts et protocoles communs pour les modèles de langage basés sur des handles pourrait conduire à la création de composants réutilisables pour travailler avec eux, comme ce qui s'est produit dans le cas d'EMF.
Ce n'est pas qu'Eclipse n'ait pas compris ces problèmes. Retour en 2005
Dans un certain sens, le projet Handly est conçu pour résoudre à peu près les mêmes problèmes qu'EMF, mais pour des modèles basés sur des handles, et principalement des modèles de langage (c'est-à-dire représentant des éléments de la structure d'un langage de programmation). Les principaux objectifs fixés lors de la conception de Handly sont répertoriés ci-dessous :
- Identification des principales abstractions du domaine.
- Réduire les efforts et améliorer la qualité de la mise en œuvre des modèles de langage basés sur des handles grâce à la réutilisation du code.
- Fournir une API de méta-niveau unifiée aux modèles résultants, permettant de créer des composants IDE communs qui fonctionnent avec des modèles basés sur des handles de langage.
- Flexibilité et évolutivité.
- Intégration avec Xtext (dans une couche séparée).
Pour mettre en évidence les concepts et protocoles communs, les implémentations existantes de modèles basés sur des descripteurs de langage ont été analysées. Les principales interfaces et implémentations de base fournies par Handly sont présentées dans la Fig. 8.
Riz. 8. Interfaces communes et implémentations de base des éléments Handly
L'interface IElement représente le handle d'un élément et est commune aux éléments de tous les modèles basés sur Handly. La classe abstraite Element implémente le mécanisme poignée/corps généralisé (Fig. 9).
Riz. 9. IElement et implémentation générique du handle/body
De plus, Handly fournit un mécanisme généralisé pour notifier les modifications apportées aux éléments du modèle (Fig. 10). Comme vous pouvez le constater, il est globalement similaire aux mécanismes de notification implémentés dans le modèle de ressource et le modèle Java, et utilise IElementDelta pour fournir une représentation unifiée des informations de modification des éléments.
Riz. 10. Interfaces générales et implémentations de base du mécanisme de notification Handly
La partie Handly discutée ci-dessus (Fig. 9 et 10) peut être utilisée pour représenter presque tous les modèles basés sur une poignée. Pour créer linguistique modèles, le projet offre des fonctionnalités supplémentaires - en particulier des interfaces communes et des implémentations de base pour les éléments de la structure du texte source, ce qu'on appelle éléments sources (Fig. 8). L'interface ISourceFile représente un fichier source et ISourceConstruct représente un élément dans le fichier source. Les classes abstraites SourceFile et SourceConstruct implémentent des mécanismes généralisés pour prendre en charge l'utilisation des fichiers sources et de leurs éléments, par exemple, travailler avec des tampons de texte, lier les coordonnées d'un élément dans le texte source, réconcilier les modèles avec le contenu actuel d'un tampon de copie de travail. , etc. La mise en œuvre de ces mécanismes est généralement un véritable défi, et Handly peut réduire considérablement les efforts de développement de modèles de langage basés sur des handles en fournissant des implémentations de base de haute qualité.
En plus des mécanismes de base répertoriés ci-dessus, Handly fournit une infrastructure pour les tampons de texte et les instantanés, la prise en charge de l'intégration avec les éditeurs de code source (y compris l'intégration prête à l'emploi avec l'éditeur Xtext), ainsi que certains composants d'interface utilisateur courants qui travailler avec des éditeurs de code source, des modèles manuels tels que le framework outline. Pour illustrer ses capacités, le projet fournit plusieurs exemples, dont une implémentation du modèle Java dans Handly. (Par rapport à l'implémentation complète du modèle Java dans JDT, ce modèle est intentionnellement quelque peu simplifié pour plus de clarté.)
Comme indiqué précédemment, lors de la conception initiale et du développement ultérieur de Handly, l'accent a été et continue d'être mis sur l'évolutivité et la flexibilité.
En principe, les modèles basés sur des poignées s'adaptent assez bien « de par leur conception ». Par exemple, l'idiome handle/body vous permet de limiter la quantité de mémoire consommée par un modèle. Mais il y a aussi des nuances. Ainsi, lors des tests d'évolutivité de Handly, un problème a été découvert dans la mise en œuvre du mécanisme de notification : lorsqu'un grand nombre d'éléments étaient modifiés, la construction de deltas prenait trop de temps. Il s'est avéré que le même problème était présent dans le modèle Java JDT, à partir duquel le code correspondant avait été adapté. Nous avons corrigé le bug dans Handly et préparé un correctif similaire pour JDT, qui a été reçu avec gratitude. Ce n'est qu'un exemple où l'introduction de Handly dans les implémentations de modèles existantes pourrait être potentiellement utile, car dans ce cas, un tel bug pourrait être corrigé à un seul endroit.
Pour rendre l’implémentation de Handly dans les implémentations de modèles existantes techniquement réalisable, la bibliothèque doit avoir une flexibilité importante. Le principal problème est de maintenir la compatibilité ascendante à travers le modèle API. Ce problème a été résolu en
La flexibilité a aussi d’autres aspects. Par exemple, Handly n'impose presque aucune restriction sur la structure du modèle et peut être utilisé pour modéliser à la fois des langages à usage général et spécifiques à un domaine. Lors de la construction de la structure du fichier source, Handly ne prescrit aucune forme particulière de représentation AST et, en principe, ne nécessite même pas la présence d'un AST lui-même, garantissant ainsi la compatibilité avec presque tous les mécanismes d'analyse. Enfin, Handly prend en charge l'intégration complète avec l'espace de travail Eclipse, mais peut également travailler directement avec les systèmes de fichiers grâce à son intégration avec
Version actuelle
Comme indiqué ci-dessus, l'un de ces produits est 1C:Enterprise Development Tools, où Handly est utilisé dès le début pour modéliser des éléments de la structure de haut niveau de langages 1C:Enterprise tels que le langage de programmation intégré et le langage de requête. . Un autre produit est moins connu du grand public. Ce
Nous espérons qu'après la sortie de la version 1.0 avec une garantie de stabilité de l'API et la sortie du projet de l'état d'incubation, Handly aura de nouveaux adoptants. Entre-temps, le projet continue de tester et d'améliorer l'API, en publiant deux versions « majeures » par an – en juin (à la même date que la version simultanée d'Eclipse) et en décembre, offrant un calendrier prévisible sur lequel les adoptants peuvent compter. Nous pouvons également ajouter que le « taux de bugs » du projet reste à un niveau constamment bas et que Handly travaille de manière fiable dans les produits des premiers utilisateurs depuis les toutes premières versions. Pour explorer davantage Eclipse Handly, vous pouvez utiliser
Source: habr.com