Prawdopodobnie,
W tym artykule, który ma charakter przeglądowy, postaramy się przyjrzeć niektórym podstawom architektury Eclipse jako platformy do budowania zintegrowanych narzędzi programistycznych i dać wstępne wyobrażenie o komponentach Eclipse, które stanowią podstawę technologii platforma dla „nowego konfiguratora” 1C: Enterprise.
Wprowadzenie do architektury Eclipse
Przyjrzyjmy się najpierw niektórym ogólnym aspektom architektury Eclipse na przykładzie
Przede wszystkim należy zauważyć, że Eclipse charakteryzuje się dość przejrzystym nawarstwieniem architektonicznym, z oddzieleniem funkcjonalności niezależnej od języka od funkcjonalności przeznaczonej do obsługi konkretnych języków programowania oraz oddzieleniem niezależnych od UI komponentów „rdzeniowych” od komponentów powiązanych z obsługą interfejsu użytkownika.
W ten sposób platforma Eclipse definiuje wspólną, niezależną od języka infrastrukturę, a narzędzia programistyczne Java dodają do Eclipse w pełni funkcjonalne środowisko Java IDE. Zarówno platforma Eclipse, jak i JDT składają się z kilku komponentów, z których każdy należy albo do „rdzenia” niezależnego od interfejsu użytkownika, albo do warstwy interfejsu użytkownika (rysunek 1).
Ryż. 1. Platforma Eclipse i JDT
Wymieńmy główne komponenty platformy Eclipse:
- Czas pracy — Definiuje infrastrukturę wtyczek. Eclipse charakteryzuje się modułową architekturą. Zasadniczo Eclipse to zbiór „punktów rozszerzeń” i „rozszerzeń”.
- Workspace — Zarządza jednym lub większą liczbą projektów. Projekt składa się z folderów i plików mapowanych bezpośrednio do systemu plików.
- Standardowy zestaw narzędzi do widżetów (SWT) - Zapewnia podstawowe elementy interfejsu użytkownika zintegrowane z systemem operacyjnym.
- JFace — Zapewnia szereg frameworków interfejsu użytkownika zbudowanych na bazie SWT.
- Workbench — Definiuje paradygmat interfejsu użytkownika Eclipse: edytory, widoki, perspektywy.
Trzeba powiedzieć, że platforma Eclipse zapewnia także wiele innych przydatnych komponentów do budowania zintegrowanych narzędzi programistycznych, w tym Debugowanie, Porównywanie, Wyszukiwanie i Zespół. Na szczególną uwagę zasługuje JFace Text - podstawa do budowy „inteligentnych edytorów” kodu źródłowego. Niestety, nawet pobieżne zbadanie tych komponentów, a także komponentów warstwy interfejsu użytkownika, nie jest możliwe w ramach tego artykułu, dlatego w pozostałej części tej sekcji ograniczymy się do przeglądu głównych „podstawowych” komponentów Platforma Eclipse i JDT.
Rdzeń wykonawczy
Na nim opiera się infrastruktura wtyczek Eclipse
Podstawowy obszar roboczy
Prawie każde zintegrowane środowisko programistyczne zbudowane na platformie Eclipse współpracuje z obszarem roboczym Eclipse. Jest to obszar roboczy, w którym zazwyczaj znajduje się kod źródłowy aplikacji opracowanej w środowisku IDE. Obszar roboczy jest odwzorowywany bezpośrednio na system plików i składa się z projektów zawierających foldery i pliki. Te projekty, foldery i pliki nazywane są Surowce obszar roboczy. Implementacja obszaru roboczego w Eclipse pełni funkcję pamięci podręcznej w stosunku do systemu plików, co pozwala znacznie przyspieszyć poruszanie się po drzewie zasobów. Dodatkowo Workspace udostępnia szereg dodatkowych usług, m.in
Komponent Core Resources (wtyczka org.eclipse.core.resources) odpowiada za obsługę obszaru roboczego i jego zasobów. W szczególności komponent ten zapewnia programowy dostęp do obszaru roboczego w formularzu modele zasobów. Aby efektywnie pracować z tym modelem, klienci potrzebują prostego sposobu przedstawienia łącza do zasobu. W takim przypadku pożądane byłoby ukrycie obiektu bezpośrednio przechowującego stan zasobu w modelu przed dostępem klienta. W przeciwnym razie w przypadku np. usunięcia pliku klient mógłby w dalszym ciągu przetrzymywać obiekt, którego nie ma już w modelu, co wiązałoby się z problemami. Eclipse rozwiązuje ten problem za pomocą czegoś o nazwie uchwyt ratunek. Handle pełni rolę klucza (zna jedynie ścieżkę do zasobu w obszarze roboczym) i całkowicie kontroluje dostęp do obiektu modelu wewnętrznego, który bezpośrednio przechowuje informację o stanie zasobu. Ten projekt jest odmianą wzoru
Ryż. Rysunek 2 ilustruje idiom Handle/Body zastosowany do modelu zasobów. Interfejs IResource reprezentuje uchwyt zasobu i jest interfejsem API, w przeciwieństwie do klasy Resource, która implementuje ten interfejs, i klasy ResourceInfo, która reprezentuje treść, a które nie są interfejsami API. Podkreślamy, że uchwyt zna jedynie ścieżkę do zasobu w stosunku do katalogu głównego obszaru roboczego i nie zawiera łącza do informacji o zasobach. Obiekty informacji o zasobach tworzą tak zwane „drzewo elementów”. Ta struktura danych jest całkowicie materializowana w pamięci. Aby znaleźć instancję informacji o zasobie odpowiadającą uchwytowi, drzewo elementów jest przeglądane zgodnie ze ścieżką zapisaną w tym uchwycie.
Ryż. 2. IResource i ResourceInfo
Jak zobaczymy później, podstawowy projekt modelu zasobów (możemy nazwać go opartym na uchwytach) jest używany w Eclipse także w innych modelach. Na razie wymieńmy niektóre charakterystyczne właściwości tego projektu:
- Uchwyt jest obiektem wartościowym. Obiekty wartości to obiekty niezmienne, których równość nie jest oparta na tożsamości. Takie obiekty można bezpiecznie wykorzystać jako klucz w zaszyfrowanych kontenerach. Wiele wystąpień uchwytu może odwoływać się do tego samego zasobu. Aby je porównać, należy użyć metody równości(Object).
- Uchwyt określa zachowanie zasobu, ale nie zawiera informacji o stanie zasobu (jedyne dane, jakie przechowuje to „klucz”, czyli ścieżka do zasobu).
- Uchwyt może odnosić się do zasobu, który nie istnieje (albo zasobu, który nie został jeszcze utworzony, albo zasobu, który został już usunięty). Istnienie zasobu można sprawdzić za pomocą metody IResource.exists().
- Niektóre operacje można zrealizować wyłącznie w oparciu o informacje zapisane w samym handle (tzw. operacje handle-only). Przykładami są IResource.getParent(), getFullPath() itp. Zasób nie musi istnieć, aby taka operacja zakończyła się sukcesem. Operacje wymagające istnienia zasobu, aby zakończyć się pomyślnie, zgłaszają wyjątek CoreException, jeśli zasób nie istnieje.
Eclipse zapewnia wydajny mechanizm powiadamiania o zmianach w zasobach obszaru roboczego (rysunek 3). Zasoby mogą ulec zmianie w wyniku działań wykonanych w samym środowisku Eclipse IDE lub w wyniku synchronizacji z systemem plików. W obu przypadkach klienci subskrybujący powiadomienia otrzymują szczegółową informację o zmianach w postaci „delt zasobów”. Delta opisuje zmiany między dwoma stanami (pod)drzewa zasobów obszaru roboczego i sama jest drzewem, którego każdy węzeł opisuje zmianę w zasobie i zawiera listę delt na następnym poziomie, które opisują zmiany w zasobach podrzędnych.
Ryż. 3. IResourceChangeEvent i IResourceDelta
Mechanizm powiadamiania oparty na deltach zasobów charakteryzuje się następującymi cechami:
- Pojedynczą zmianę i wiele zmian opisano przy użyciu tej samej struktury, ponieważ delta jest budowana w oparciu o zasadę kompozycji rekurencyjnej. Klienci subskrybenci mogą przetwarzać powiadomienia o zmianie zasobów przy użyciu rekurencyjnego opadania przez drzewo delt.
- Delta zawiera pełną informację o zmianach w zasobie, w tym o jego ruchu i/lub zmianach w powiązanych z nim „znacznikach” (na przykład błędy kompilacji są reprezentowane jako znaczniki).
- Ponieważ odniesienia do zasobów są tworzone poprzez uchwyt, delta może naturalnie odwoływać się do zdalnego zasobu.
Jak wkrótce się przekonamy, główne elementy projektu mechanizmu powiadamiania o zmianach w modelu zasobów mają zastosowanie także w przypadku innych modeli opartych na uchwytach.
Rdzeń JDT
Model zasobów obszaru roboczego Eclipse jest podstawowym modelem niezależnym od języka. Komponent JDT Core (wtyczka org.eclipse.jdt.core) udostępnia API do nawigacji i analizowania struktury obszaru roboczego z perspektywy Java, tzw. „model Java” (Model Javy). Ten interfejs API jest zdefiniowany w kategoriach elementów Java, w przeciwieństwie do podstawowego interfejsu API modelu zasobów, który jest zdefiniowany w kategoriach folderów i plików. Główne interfejsy drzewa elementów Java pokazano na rys. 4.
Ryż. 4. Elementy modelu Java
Model Java wykorzystuje ten sam idiom uchwytu/treści co model zasobów (rysunek 5). IJavaElement jest uchwytem, a JavaElementInfo pełni rolę treści. Interfejs IJavaElement definiuje protokół wspólny dla wszystkich elementów Java. Niektóre z jego metod obsługują tylko uchwyt: getElementName(), getParent() itp. Obiekt JavaElementInfo przechowuje stan odpowiedniego elementu: jego strukturę i atrybuty.
Ryż. 5. IJavaElement i JavaElementInfo
Model Java ma pewne różnice w implementacji podstawowego projektu uchwytu/korpusu w porównaniu z modelem zasobów. Jak zauważono powyżej, w modelu zasobów drzewo elementów, którego węzły są obiektami informacji o zasobach, jest w całości zawarte w pamięci. Jednak model Java może mieć znacznie większą liczbę elementów niż drzewo zasobów, ponieważ reprezentuje również wewnętrzną strukturę plików .java i .class: typy, pola i metody.
Aby uniknąć całkowitej materializacji całego drzewa elementów w pamięci, implementacja modelu Java wykorzystuje pamięć podręczną LRU o ograniczonym rozmiarze zawierającą informacje o elementach, gdzie kluczem jest uchwyt IJavaElement. obiekty informacji o elementach są tworzone na żądanie podczas nawigacji po drzewie elementów. W takim przypadku najrzadziej używane elementy są usuwane z pamięci podręcznej, a zużycie pamięci przez model pozostaje ograniczone do określonego rozmiaru pamięci podręcznej. To kolejna zaleta projektowania opartego na uchwytach, które całkowicie ukrywa takie szczegóły implementacji przed kodem klienta.
Mechanizm powiadamiania o zmianach w elementach Java jest ogólnie podobny do mechanizmu śledzenia zmian w zasobach obszaru roboczego omówionego powyżej. Klient chcący monitorować zmiany w modelu Java subskrybuje powiadomienia, które są reprezentowane jako obiekt ElementChangedEvent zawierający obiekt IJavaElementDelta (rysunek 6).
Ryż. 6. ElementChangedEvent i IJavaElementDelta
Model Java nie zawiera informacji o treściach metod ani rozpoznawaniu nazw, dlatego do szczegółowej analizy kodu napisanego w Javie JDT Core udostępnia dodatkowy (nieoparty na uchwytach) model:
Ponieważ drzewa składni mogą zużywać znaczną ilość pamięci, JDT buforuje tylko jedną funkcję AST dla aktywnego edytora. W przeciwieństwie do modelu Java, AST jest zwykle postrzegany jako model „pośredni”, „tymczasowy”, do którego elementów klienci nie powinni odwoływać się poza kontekstem operacji, która doprowadziła do utworzenia AST.
Wymienione trzy modele (model Java, AST, powiązania) razem tworzą podstawę do budowy „inteligentnych narzędzi programistycznych” w JDT, w tym potężnego edytora Java z różnymi „pomocnikami”, różnymi akcjami przetwarzania kodu źródłowego (w tym organizowaniem listy importowanych nazwy i formatowanie według indywidualnego stylu), narzędzia wyszukiwania i refaktoryzacji. W tym przypadku model Java odgrywa szczególną rolę, ponieważ to na nim opiera się wizualna reprezentacja struktury tworzonej aplikacji (na przykład w Eksploratorze pakietów, Konspekcie, Wyszukiwaniu, Hierarchii połączeń i Hierarchia typów).
Komponenty Eclipse używane w 1C:Enterprise Development Tools
Na ryc. Rysunek 7 przedstawia komponenty Eclipse, które stanowią podstawę platformy technologicznej dla 1C:Enterprise Development Tools.
Ryż. 7. Eclipse jako platforma dla 1C:Enterprise Development Tools
Platforma Zaćmienie zapewnia podstawową infrastrukturę. Niektórym aspektom tej infrastruktury przyjrzeliśmy się w poprzedniej sekcji.
Jak każde narzędzie naprawdę ogólnego przeznaczenia, EMF nadaje się do rozwiązywania szerokiego zakresu problemów modelowania, ale niektóre klasy modeli (na przykład omówione powyżej modele oparte na uchwytach) mogą wymagać bardziej wyspecjalizowanych narzędzi do modelowania. Opowiadanie o PEM jest niewdzięcznym zadaniem, zwłaszcza w ramach jednego artykułu, gdyż jest to temat na osobną książkę, i to dość obszerną. Zauważmy tylko, że wysokiej jakości system uogólnień leżący u podstaw EMF pozwolił na narodziny całej gamy projektów poświęconych modelowaniu, które zaliczają się do projektu najwyższego poziomu
1C: Enterprise Development Tools aktywnie wykorzystuje zarówno sam EMF, jak i wiele innych projektów Eclipse Modeling. W szczególności Xtext jest jednym z fundamentów narzędzi programistycznych dla takich języków 1C:Enterprise, jak wbudowany język programowania i język zapytań. Kolejną podstawą tych narzędzi programistycznych jest projekt Eclipse Handly, który omówimy bardziej szczegółowo (spośród wymienionych komponentów Eclipse jest on wciąż najmniej znany).
Podstawowe zasady architektury modeli opartych na uchwytach, takie jak idiom uchwyt/treść, zostały omówione powyżej na przykładach modelu zasobów i modelu Java. Zauważono również, że zarówno model zasobów, jak i model Java stanowią ważne podstawy narzędzi programistycznych Eclipse Java (JDT). A ponieważ prawie wszystkie projekty *DT Eclipse mają architekturę podobną do JDT, nie będzie wielką przesadą stwierdzenie, że modele oparte na uchwytach leżą u podstaw wielu, jeśli nie wszystkich IDE zbudowanych na platformie Eclipse. Na przykład narzędzie programistyczne Eclipse C/C++ Development Tooling (CDT) ma model C/C++ oparty na uchwytach, który odgrywa tę samą rolę w architekturze CDT, co model Java w JDT.
Przed Handly Eclipse nie oferował wyspecjalizowanych bibliotek do budowania modeli językowych opartych na uchwytach. Obecnie istniejące modele powstały głównie poprzez bezpośrednią adaptację kodu modelu Java (tzw. kopiuj/wklej), w przypadkach, gdy na to pozwala Licencja publiczna Eclipse (EPL). (Oczywiście zwykle nie jest to problem prawny w przypadku, powiedzmy, samych projektów Eclipse, ale nie w przypadku produktów o zamkniętym kodzie źródłowym.) Oprócz nieodłącznej przypadkowości, technika ta wprowadza dobrze znane problemy: duplikację kodu wprowadzaną podczas dostosowywania się do błędów, itp. Co gorsza, powstałe modele pozostają „rzeczami samymi w sobie” i nie wykorzystują potencjału unifikacji. Jednak wyodrębnienie wspólnych koncepcji i protokołów dla modeli języków opartych na uchwytach mogłoby doprowadzić do stworzenia komponentów wielokrotnego użytku do pracy z nimi, podobnie jak to miało miejsce w przypadku EMF.
To nie tak, że Eclipse nie rozumiał tych problemów. W 2005 roku
W pewnym sensie projekt Handly ma na celu rozwiązanie w przybliżeniu tych samych problemów, co EMF, ale dla modeli opartych na uchwytach, i to przede wszystkim językowych (czyli reprezentujących elementy struktury jakiegoś języka programowania). Poniżej wymieniono główne cele stawiane sobie przy projektowaniu Handly:
- Identyfikacja głównych abstrakcji z obszaru tematycznego.
- Zmniejszenie wysiłku i poprawa jakości wdrażania modeli języków opartych na uchwytach poprzez ponowne wykorzystanie kodu.
- Zapewnienie ujednoliconego interfejsu API na poziomie meta dla wynikowych modeli, umożliwiając tworzenie wspólnych komponentów IDE, które współpracują z modelami opartymi na uchwytach językowych.
- Elastyczność i skalowalność.
- Integracja z Xtext (w osobnej warstwie).
Aby podkreślić wspólne koncepcje i protokoły, przeanalizowano istniejące implementacje modeli opartych na uchwytach językowych. Główne interfejsy i podstawowe implementacje udostępniane przez Handly pokazano na rys. 8.
Ryż. 8. Wspólne interfejsy i podstawowe implementacje elementów Handly
Interfejs IElement reprezentuje uchwyt elementu i jest wspólny dla elementów wszystkich modeli opartych na Handly. Klasa abstrakcyjna Element implementuje uogólniony mechanizm uchwyt/korpus (rys. 9).
Ryż. 9. IElement i ogólna implementacja uchwytu/korpusu
Dodatkowo Handly udostępnia uogólniony mechanizm powiadamiania o zmianach w elementach modelu (rys. 10). Jak widać, jest on zasadniczo podobny do mechanizmów powiadamiania zaimplementowanych w modelu zasobów i modelu Java i wykorzystuje IElementDelta w celu zapewnienia ujednoliconej reprezentacji informacji o zmianie elementu.
Ryż. 10. Ogólne interfejsy i podstawowe implementacje mechanizmu powiadomień Handly
Omówioną powyżej część Handly (rys. 9 i 10) można wykorzystać do przedstawienia niemal dowolnych modeli opartych na uchwytach. Do tworzenia lingwistyczny modele, projekt oferuje dodatkową funkcjonalność – w szczególności wspólne interfejsy i podstawowe implementacje elementów struktury tekstu źródłowego, tzw. elementy źródłowe (ryc. 8). Interfejs ISourceFile reprezentuje plik źródłowy, a ISourceConstruct reprezentuje element w pliku źródłowym. Klasy abstrakcyjne SourceFile i SourceConstruct implementują uogólnione mechanizmy wspierające pracę z plikami źródłowymi i ich elementami, na przykład pracę z buforami tekstowymi, wiązanie ze współrzędnymi elementu w tekście źródłowym, uzgadnianie modeli z bieżącą zawartością bufora kopii roboczej itp. Implementacja tych mechanizmów jest zwykle sporym wyzwaniem, a Handly może znacznie zmniejszyć wysiłek związany z opracowywaniem modeli języków opartych na uchwytach, zapewniając wysokiej jakości implementacje podstawowe.
Oprócz podstawowych mechanizmów wymienionych powyżej, Handly zapewnia infrastrukturę dla buforów tekstu i migawek, obsługę integracji z edytorami kodu źródłowego (w tym gotową integrację z edytorem Xtext), a także niektóre typowe komponenty interfejsu użytkownika, które współpracuj z edytorami kodu źródłowego.Poręczne modele, takie jak framework konspektu. Aby zilustrować jego możliwości, projekt podaje kilka przykładów, w tym implementację modelu Java w Handly. (W porównaniu z pełną implementacją modelu Java w JDT, model ten został celowo nieco uproszczony dla większej przejrzystości.)
Jak wspomniano wcześniej, podczas początkowego projektowania i późniejszego rozwoju Handly skupiano się i nadal skupia się na skalowalności i elastyczności.
W zasadzie modele oparte na uchwytach całkiem dobrze skalują się „z założenia”. Na przykład idiom uchwyt/treść pozwala ograniczyć ilość pamięci zużywanej przez model. Ale są też niuanse. Tym samym, testując Handly pod kątem skalowalności, odkryto problem w implementacji mechanizmu powiadomień – przy zmianie dużej liczby elementów konstruowanie delt zajmowało zbyt dużo czasu. Okazało się, że ten sam problem występował w modelu Java JDT, z którego kiedyś zaadaptowano odpowiedni kod. Naprawiliśmy błąd w Handly i przygotowaliśmy podobną łatkę dla JDT, która została przyjęta z wdzięcznością. To tylko jeden przykład, gdzie wprowadzenie Handly do istniejących implementacji modeli mogłoby być potencjalnie przydatne, ponieważ w tym przypadku taki błąd można by naprawić w jednym miejscu.
Aby wdrożenie Handly w istniejących implementacjach modeli było technicznie wykonalne, biblioteka musi charakteryzować się znaczną elastycznością. Głównym problemem jest utrzymanie kompatybilności wstecznej w całym modelu API. Problem ten został rozwiązany w
Elastyczność ma także inne aspekty. Na przykład Handly nie nakłada prawie żadnych ograniczeń na strukturę modelu i może być używany do modelowania zarówno języków ogólnego przeznaczenia, jak i języków specyficznych dla domeny. Konstruując strukturę pliku źródłowego, Handly nie zaleca żadnej szczególnej formy reprezentacji AST i w zasadzie nie wymaga nawet obecności samego AST, zapewniając w ten sposób kompatybilność z niemal każdym mechanizmem analizowania. Wreszcie Handly obsługuje pełną integrację z obszarem roboczym Eclipse, ale może także pracować bezpośrednio z systemami plików dzięki integracji z
Obecna wersja
Jak wspomniano powyżej, jednym z takich produktów jest 1C:Enterprise Development Tools, gdzie Handly jest używany od samego początku do modelowania elementów struktury wysokiego poziomu takich języków 1C:Enterprise jako wbudowany język programowania i język zapytań . Kolejny produkt jest mniej znany ogółowi społeczeństwa. Ten
Mamy nadzieję, że po wydaniu wersji 1.0 z gwarancją stabilności API i wyjściu projektu ze stanu inkubacji, Handly zyska nowych zwolenników. W międzyczasie projekt kontynuuje testowanie i dalsze ulepszanie interfejsu API, wypuszczając dwie „główne” wydania rocznie – w czerwcu (w tym samym dniu, co jednoczesne wydanie Eclipse) i w grudniu, zapewniając przewidywalny harmonogram, na którym mogą polegać użytkownicy. Możemy również dodać, że „wskaźnik błędów” projektu utrzymuje się na niezmiennie niskim poziomie, a Handly niezawodnie współpracuje z produktami wczesnych użytkowników już od pierwszych wersji. Aby dokładniej poznać Eclipse Handly, możesz użyć
Źródło: www.habr.com