Мабуть,
У цій статті, оглядовій за своїм характером, ми спробуємо розглянути деякі основи архітектури Eclipse як платформи для побудови інтегрованих засобів розробки та дати початкове уявлення про компоненти Eclipse, що утворюють фундамент технологічної платформи для нового конфігуратора 1C: Підприємство,
Введення в архітектуру Eclipse
Розглянемо спочатку деякі загальні аспекти архітектури Eclipse з прикладу
Насамперед слід зазначити, що для Eclipse характерно досить чітке архітектурне розшарування, з відділенням мовно-незалежної функціональності від функціональності, призначеної для підтримки конкретних мов програмування, та відділенням UI-незалежних «ядерних» (core) компонент від компонентів, пов'язаних з підтримкою користувача інтерфейсу.
Так, Eclipse Platform визначає загальну, мовно-незалежну інфраструктуру, а Java development tools додають до Eclipse повнофункціональну Java IDE. Як Eclipse Platform, так і JDT складаються з декількох компонентів, кожна з яких відноситься або до UI-незалежного "ядра", або до шару UI (рис. 1).
Мал. 1. Eclipse Platform та JDT
Перерахуємо основні компоненти Eclipse Platform:
- Час виконання - Визначає інфраструктуру плагінів. Для Eclipse характерна модульна архітектура. По суті, Eclipse є колекцією "точок розширення" та "розширень".
- Робоча область — Керує одним чи кількома проектами. Проект складається з папок та файлів, які відображаються безпосередньо на файлову систему.
- Standard Widget Toolkit (SWT) — Надає базові елементи інтерфейсу користувача, інтегровані з операційною системою.
- JFace — Надає ряд UI фреймворків, побудованих поверх SWT.
- Верстак - Визначає UI-парадигму Eclipse: редактори, уявлення, перспективи.
Потрібно сказати, що Eclipse Platform надає безліч інших корисних компонент для побудови інтегрованих засобів розробки, серед яких можна відзначити Debug, Compare, Search, і Team. Окремо слід згадати JFace Text – основу для побудови розумних редакторів вихідного коду. На жаль, навіть побіжний розгляд цих компонент, так само як і компонент UI-шару не є можливим у рамках цієї статті, тому в частині цього розділу, що залишилася, ми обмежимося оглядом основних «ядерних» компонент Eclipse Platform і JDT.
Core Runtime
Інфраструктура плагінів Eclipse заснована на
Core Workspace
Практично будь-яке інтегроване середовище розробки, побудоване на основі Eclipse Platform працює з Eclipse workspace. Саме workspace зазвичай містить вихідний код програми, що розробляється в IDE. Workspace безпосередньо відображається на файлову систему і складається з проектів, які містять папки та файли. Ці проекти, папки та файли називаються ресурсами workspace. Реалізація workspace в Eclipse служить кешем по відношенню до файлової системи, що дозволяє помітно прискорити обхід дерева ресурсів. Крім того, workspace надає низку додаткових сервісів, включаючи
За підтримку workspace та його ресурсів відповідає компонент Core Resources (плагін org.eclipse.core.resources). Зокрема, ця компонента надає програмний доступ до workspace у вигляді моделі ресурсів. Для ефективної роботи з цією моделлю клієнтам потрібен простий спосіб подання посилання ресурс. При цьому об'єкт, що безпосередньо зберігає стан ресурсу в моделі, бажано було б сховати від клієнтського доступу. Інакше, у разі, наприклад, видалення файлу, клієнт міг би продовжувати утримувати об'єкт, якого вже немає в моделі, з проблемами, що випливають звідси. Eclipse вирішує це завдання, використовуючи так званий обробляти ресурсу. Handle виступає в ролі ключа (він знає лише шлях до ресурсу у workspace) і повністю контролює доступ до внутрішнього об'єкта моделі, що безпосередньо зберігає інформацію про стан ресурсу. Даний дизайн є варіацією патерну.
Мал. 2 ілюструє ідіому Handle/Body стосовно моделі ресурсів. Інтерфейс IResource являє собою handle ресурсу і є API, на відміну від класу Resource, що реалізує цей інтерфейс, а також класу ResourceInfo, що представляє body, які API не є. Підкреслимо, що handle знає лише шлях до ресурсу щодо кореня workspace і не містить посилання на resource info. Об'єкти resource info утворюють так зване дерево елементів (element tree). Ця структура даних повністю матеріалізована у пам'яті. Щоб знайти екземпляр resource info, відповідний деякому handle, element tree обходиться відповідно до способу, що зберігається в цьому handle.
Мал. 2. IResource та ResourceInfo
Як ми побачимо, базовий дизайн моделі ресурсів (можна назвати його handle-based) використовується в Eclipse і для інших моделей. А поки що перерахуємо деякі відмінні властивості цього дизайну:
- Handle є об'єктом-значенням (value object). Об'єкти-значення – це немутабельні (immutable) об'єкти, рівність яких не ґрунтується на ідентичності. Такі об'єкти можуть безпечно використовуватися як ключ у хешованих контейнерах. Декілька екземплярів handle можуть посилатися на той самий ресурс. Для порівняння необхідно використовувати метод equals(Object).
- Handle визначає поведінку ресурсу, але містить інформацію про стан ресурсу (єдині дані, які він зберігає, це «ключ», шлях до ресурсу).
- Handle може посилатися на неіснуючий ресурс (або ресурс, який ще створений, або ресурс, який вже видалено). Існування ресурсу можна перевірити за допомогою IResource.exists().
- Деякі операції можуть бути реалізовані виходячи виключно з інформації, що зберігається в самому handle (так звані handle-only операції). Прикладами є IResource.getParent(), getFullPath() тощо. Ресурс необов'язково існуватиме для успішного виконання такої операції. Операції, для успішного виконання яких потрібно, щоб існував ресурс, викидають виняток (CoreException), якщо ресурс не існує.
Eclipse надає ефективний механізм нотифікації про зміни ресурсів workspace (рис. 3). Ресурси можуть змінюватися як в результаті дій, що виконуються в Eclipse IDE, так і в результаті синхронізації з файловою системою. В обох випадках клієнтам, що підписалися на нотифікації, надається детальна інформація про зміни у вигляді «ресурсних дельт» (resource delta). Дельта описує зміни між двома станами (під-)дерева ресурсів workspace і сама є деревом, кожен вузол якого описує зміну деякого ресурсу та містить список дельт наступного рівня, що описують зміни дочірніх ресурсів.
Мал. 3. IResourceChangeEvent та IResourceDelta
Заснований на ресурсних дельтах механізм нотифікації має такі характеристики:
- Єдина зміна та безліч змін описуються за допомогою однієї і тієї ж структури, оскільки дельта будується за принципом рекурсивної композиції. Клієнти-передплатники можуть опрацьовувати нотифікації про зміну ресурсів за допомогою рекурсивного спуску по дереву дельт.
- Дельта містить повну інформацію про зміну ресурсу, включаючи його переміщення та/або зміну асоційованих з ним «маркерів» (у вигляді маркерів надаються, наприклад, помилки компіляції).
- Оскільки посилання на ресурс робляться через handle, дельта може природно посилатися на віддалений ресурс.
Як ми незабаром побачимо, основні складові дизайну механізму нотифікації про зміну моделі ресурсів є актуальними і для інших handle-based моделей.
Ядро JDT
Модель ресурсів Eclipse workspace є основною мовно-незалежною моделлю. Компонент JDT Core (плагін org.eclipse.jdt.core) надає API для навігації та аналізу структури workspace з точки зору Java, так звану «модель Java» (Java model). Цей API визначений у термінах елементів Java, на відміну від нижченаведеного API моделі ресурсів, який визначений у термінах папок та файлів. Основні інтерфейси дерева елементів Java зображені на рис. 4.
Мал. 4. Елементи моделі Java
Модель Java використовує ту ж ідіому handle/body, що і модель ресурсів (рис. 5). IJavaElement – це handle, а JavaElementInfo грає роль body. Інтерфейс IJavaElement визначає протокол, загальний всім елементів Java. Деякі з його методів є handle-only: getElementName(), getParent() і т.п. Об'єкт JavaElementInfo зберігає стан відповідного елемента: його структуру та атрибути.
Мал. 5. IJavaElement та JavaElementInfo
Модель Java має деякі відмінності у реалізації базового дизайну handle/body у порівнянні з моделлю ресурсів. Як зазначалося вище, моделі ресурсів element tree, вузлами якого є об'єкти resource info, повністю міститься в пам'яті. Але в моделі Java може бути значно більше елементів, ніж у дереві ресурсів, адже в ній представлена, в тому числі, і внутрішня структура .java і .class файлів: типи, поля та методи.
Щоб уникнути повної матеріалізації всього дерева елементів у пам'яті, реалізація моделі Java використовує обмежений LRU-кеш element info, де ключом є handle IJavaElement. Об'єкти element info створюються за запитом у міру того, як відбувається навігація дерева елементів. При цьому найменш часто використовувані елементи витісняються з кешу і споживання пам'яті моделлю залишається обмеженим заданим розміром кеша. Це ще одна перевага handle-based дизайну, який повністю приховує такі подробиці реалізації клієнтського коду.
Механізм нотифікації про зміну елементів Java загалом аналогічний розглянутому вище механізму відстеження змін ресурсів workspace. Клієнт, який бажає відстежувати зміни в моделі Java, підписується на нотифікації, які подаються у вигляді об'єкта ElementChangedEvent, який містить IJavaElementDelta (рис. 6).
Мал. 6. ElementChangedEvent і IJavaElementDelta
Модель Java не містить інформацію про тіло методів або роздільну здатність імен, тому для детального аналізу коду, написаного на Java, JDT Core надає додаткову (не handle-based) модель:
Оскільки синтаксичні дерева можуть споживати значну кількість пам'яті, JDT кешує лише одне AST для активного редактора. На відміну від моделі Java, AST зазвичай розглядається як «проміжна», «тимчасова» модель, елементи якої клієнтам не слід утримувати посилання поза контекстом операції, що призвела до створення AST.
Перелічені три моделі (Java model, AST, bindings) спільно є основою для побудови «інтелектуальних засобів розробки» в JDT, серед яких потужний редактор Java з різноманітними «помічниками», різні дії з обробки вихідного коду (серед яких організація списку імпорту імен та форматування відповідно до налаштованого стилю), інструменти пошуку та рефакторингу. При цьому модель Java грає особливу роль, оскільки саме вона використовується як основа для візуального представлення структури програми, що розробляється (наприклад, в Package Explorer, Outline, Search, Call Hierarchy, і Type Hierarchy).
Компоненти Eclipse, що використовуються в 1С:Enterprise Developments Tools
На рис. 7 показані компоненти Eclipse, що утворюють фундамент технологічної платформи для 1C: Enterprise Development Tools.
Мал. 7. Eclipse як платформа для 1С: Enterprise Development Tools
Платформа Eclipse надає базову інфраструктуру. Ми розглянули деякі аспекти цієї інфраструктури у попередньому розділі.
Як будь-який по-справжньому універсальний інструмент, EMF підходить для вирішення широкого спектру завдань, пов'язаних з моделюванням, але деякі класи моделей (наприклад, розглянуті вище handle-based моделі) можуть потребувати більш спеціалізованих засобів моделювання. Розповідати про EMF – заняття невдячне, особливо в обмежених рамках однієї статті, оскільки це є предметом окремої книги, і досить товстою. Зазначимо тільки, що якісна система узагальнень, покладена в основу EMF, дозволила з'явитися світ цілому спектру проектів, присвячених моделюванню, які входять до проекту верхнього рівня.
1С:Enterprise Development Tools активно використовують як EMF сам по собі, так і низку інших проектів Eclipse Modeling. Зокрема, Xtext є однією з основ засобів розробки для таких мов 1С:Підприємство, як вбудована мова програмування та мова запитів. Іншою основою цих засобів розробки є проект Eclipse Handly, на якому ми зупинимося докладніше (з перерахованих компонентів Eclipse він поки що найменш відомий).
Основні архітектурні принципи handle-based моделей, такі як ідіома handle/body, розглядалися вище на прикладі моделі ресурсів та Java-моделі. Також відзначалося, що і модель ресурсів, і модель Java є важливими основами для Eclipse Java development tools (JDT). А оскільки практично всі *DT проекти Eclipse мають аналогічну архітектуру JDT, то не буде великим перебільшенням сказати, що handle-based моделі лежать в основі багатьох, якщо не всіх IDE, побудованих поверх Eclipse Platform. Наприклад, в Eclipse C/C++ Development Tooling (CDT) є handle-based модель C/C++, що грає в архітектурі CDT ту саму роль, що і Java-модель в JDT.
До появи Handly, Eclipse не пропонував спеціалізованих бібліотек для побудови мовних handle-based моделей. Існуючі зараз моделі створювалися переважно за допомогою безпосередньої адаптації коду Java-моделі (aka copy/paste), у тих випадках, коли це дозволяє Eclipse Public License (EPL). (Зрозуміло, що, скажімо, для проектів самого Eclipse це зазвичай не є проблемою з юридичної точки зору, чого не скажеш про продукти із закритим вихідним кодом.) Крім характерної для неї безсистемності, така методика призводить до добре відомих проблем: дублювання коду, привнесеного при адаптації помилок і т.п. Що ще гірше, результуючі моделі залишаються «річчю в собі» і не використовують наявний потенціал для уніфікації. Адже виділення загальних понять та протоколів для мовних handle-based моделей могло б призвести до створення повторно використовуваних компонентів для роботи з ними, аналогічно тому, як це сталося у випадку з EMF.
Не можна сказати, що у Eclipse не було розуміння цих проблем. Ще 2005 року
У певному сенсі, проект Handly покликаний вирішувати приблизно ті ж завдання, що і EMF, але для handle-based моделей, і в першу чергу мовних (тобто елементів структури деякої мови програмування). Нижче наведено основні цілі, що ставилися при проектуванні Handly:
- Виділення основних абстракцій предметної галузі.
- Скорочення зусиль та підвищення якості реалізації мовних handle-based моделей за рахунок повторного використання коду.
- Надання уніфікованого API мета-рівня до результуючих моделей, що уможливлює створення спільних компонентів IDE, що працюють з мовними handle-based моделями.
- Гнучкість та масштабованість.
- Інтеграція з Xtext (в окремому шарі).
Для виділення загальних понять та протоколів було проаналізовано існуючі реалізації мовних handle-based моделей. Основні інтерфейси та базові реалізації, що надаються Handly, показані на рис. 8.
Мал. 8. Загальні інтерфейси та базові реалізації елементів Handly
Інтерфейс IElement являє собою handle елемента і є загальним для елементів всіх моделей, заснованих на Handly. Абстрактний клас Element реалізує узагальнений механізм handle/body (рис. 9).
Мал. 9. IElement та узагальнена реалізація handle/body
Крім того, Handly надає узагальнений механізм нотифікації про зміну елементів моделі (рис. 10). Як можна бачити, загалом він аналогічний механізмам нотифікації, реалізованим у моделі ресурсів і Java-моделі, і використовує IElementDelta для уніфікованого представлення інформації про зміну елемента.
Мал. 10. Загальні інтерфейси та базові реалізації механізму нотифікації Handly
Розглянута вище частина Handly (рис. 9 та 10) може використовуватися для представлення практично будь-яких handle-based моделей. Для створення мовних моделей проект пропонує додаткову функціональність – зокрема, загальні інтерфейси та базові реалізації для елементів структури вихідного тексту, так званих source elements (Рис. 8). Інтерфейс ISourceFile представляє вихідний файл, а ISourceConstruct – елемент усередині вихідного файла. Абстрактні класи SourceFile та SourceConstruct реалізують узагальнені механізми для підтримки роботи з вихідними файлами та їх елементами, наприклад, роботу з текстовими буферами, прив'язку до координат елемента у вихідному тексті, reconciling моделі з поточним вмістом буфера working copy тощо. Реалізація цих механізмів зазвичай є досить непростим завданням, і Handly може суттєво скоротити зусилля розробки мовних handle-based моделей за рахунок надання якісних базових реалізацій.
Крім перелічених вище основних механізмів, Handly надає інфраструктуру текстових буферів та «знімків» (snapshots), підтримку інтеграції з редакторами вихідного коду (включаючи реалізовану «з коробки» інтеграцію з Xtext editor), а також деякі спільні UI-компоненти, що працюють із заснованими на Handly моделями, такі як outline framework. Для ілюстрації своїх можливостей проект надає кілька прикладів, зокрема й реалізацію моделі Java на Handly. (У порівнянні з повною реалізацією Java-моделі в JDT, ця модель навмисно спрощена для більшої наочності.)
Як було зазначено раніше, серйозна увага при початковому проектуванні Handly та подальшому розвитку приділялася і продовжує приділятися масштабованості та гнучкості.
Загалом, handle-based моделі досить добре масштабуються “by design”. Наприклад, ідіома handle/body дозволяє обмежити кількість споживаної моделі пам'яті. Але є й нюанси. Так, при випробуваннях Handly на масштабованість була виявлена проблема реалізації механізму нотифікації – при зміні великої кількості елементів побудова дельт займала занадто багато часу. Виявилося, що та сама проблема присутня і в Java-моделі JDT, з якої був свого часу адаптований відповідний код. Ми виправили помилку у Handly та підготували аналогічний патч для JDT, який був з вдячністю прийнятий. Це лише один із прикладів, коли впровадження Handly в існуючі реалізації моделей могло б бути потенційно корисним, адже в цьому випадку таку помилку можна було б виправити лише в одному місці.
Щоб зробити впровадження Handly в існуючі реалізації моделей технічно можливим, бібліотека повинна мати значну гнучкість. Основна проблема полягає в тому, щоб зберегти зворотну сумісність API моделі. Це завдання було вирішено у
Гнучкість має інші аспекти. Наприклад, Handly майже не накладає обмежень на структуру моделі та може використовуватися як для моделювання мов загального призначення, так і для предметно-орієнтованих мов. При побудові структури вихідного файлу, Handly не наказує якусь певну форму подання AST і в принципі не вимагає навіть наявності AST, забезпечуючи, таким чином, сумісність з практично будь-якими механізмами синтаксичного аналізу. Нарешті, Handly підтримує повноцінну інтеграцію з Eclipse workspace, але також може працювати і безпосередньо з файловими системами завдяки інтеграції з
Поточна версія
Як зазначалося вище, один із цих продуктів – 1C:Enterprise Development Tools, де Handly із самого початку використовується для моделювання елементів високорівневої структури таких мов 1С:Підприємство, як вбудована мова програмування та мова запитів. Інший продукт менш відомий широкому загалу. Це
Сподіваємося, що після випуску версії 1.0 з гарантією стабільності API та виходом проекту зі стану інкубації у Handly з'являться і нові адоптери. Поки ж проект продовжує обкатування та подальше вдосконалення API, випускаючи по два «великі» релізи на рік – у червні (у ту ж дату, що й одночасний реліз Eclipse) та грудні, забезпечуючи передбачуваний графік, на який можуть покладатися адоптери. Можна ще додати, що показник "bug rate" проекту залишається на стабільно низькому рівні і Handly з перших версій надійно працює у продуктах ранніх адоптерів. Для подальшого знайомства з Eclipse Handly можна використовувати
Джерело: habr.com