Poate,
În acest articol, care este o privire de ansamblu în natură, vom încerca să analizăm câteva dintre elementele de bază ale arhitecturii Eclipse ca platformă pentru construirea de instrumente de dezvoltare integrate și să dăm o idee inițială despre componentele Eclipse care formează baza tehnologiei. platformă pentru „noul configurator” 1C: Enterprise.
Introducere în arhitectura Eclipse
Să ne uităm mai întâi la câteva aspecte generale ale arhitecturii Eclipse folosind exemplul
În primul rând, trebuie remarcat faptul că Eclipse se caracterizează printr-o stratificare arhitecturală destul de clară, cu separarea funcționalității independente de limbaj de funcționalitatea concepută pentru a suporta limbaje de programare specifice și separarea componentelor „core” independente de UI de componentele asociate. cu interfață de utilizator suport.
Astfel, Platforma Eclipse definește o infrastructură comună, independentă de limbaj, iar instrumentele de dezvoltare Java adaugă un IDE Java complet la Eclipse. Atât platforma Eclipse, cât și JDT-ul constau din mai multe componente, fiecare aparținând fie unui „nucleu” independent de UI, fie unui strat UI (Figura 1).
Orez. 1. Platforma Eclipse și JDT
Să enumerăm principalele componente ale platformei Eclipse:
- Runtime — Definește infrastructura pluginului. Eclipse se caracterizează printr-o arhitectură modulară. În esență, Eclipse este o colecție de „puncte de extensie” și „extensii”.
- Spațiu de lucru — Gestionează unul sau mai multe proiecte. Un proiect este format din foldere și fișiere care sunt mapate direct la sistemul de fișiere.
- Setul de instrumente Widget standard (SWT) - Oferă elemente de bază ale interfeței cu utilizatorul integrate cu sistemul de operare.
- JFace — Oferă un număr de cadre de UI construite pe SWT.
- Banc de lucru — Definește paradigma Eclipse UI: editori, vederi, perspective.
Trebuie spus că Platforma Eclipse oferă și multe alte componente utile pentru construirea de instrumente de dezvoltare integrate, inclusiv Debug, Compare, Search și Team. O mențiune specială trebuie făcută pentru JFace Text - baza pentru construirea „editoarelor inteligente” de cod sursă. Din păcate, chiar și o examinare superficială a acestor componente, precum și a componentelor stratului UI, nu este posibilă în scopul acestui articol, așa că în restul acestei secțiuni ne vom limita la o prezentare generală a principalelor componente „de bază” ale Platforma Eclipse și JDT.
Core Runtime
Infrastructura pluginului Eclipse se bazează pe
Spațiul de lucru principal
Aproape orice mediu de dezvoltare integrat construit pe platforma Eclipse funcționează cu spațiul de lucru Eclipse. Este spațiul de lucru care conține de obicei codul sursă al aplicației dezvoltate în IDE. Spațiul de lucru se mapează direct la sistemul de fișiere și constă din proiecte care conțin foldere și fișiere. Aceste proiecte, foldere și fișiere sunt numite resurse spațiu de lucru. Implementarea spațiului de lucru în Eclipse servește ca cache în legătură cu sistemul de fișiere, ceea ce face posibilă accelerarea semnificativă a traversării arborelui de resurse. În plus, spațiul de lucru oferă o serie de servicii suplimentare, inclusiv
Componenta Core Resources (plugin-ul org.eclipse.core.resources) este responsabilă pentru susținerea spațiului de lucru și a resurselor acestuia. În special, această componentă oferă acces programatic la spațiul de lucru din formular modele de resurse. Pentru a lucra eficient cu acest model, clienții au nevoie de o modalitate simplă de a prezenta un link către o resursă. În acest caz, ar fi de dorit să se ascundă obiectul care stochează direct starea resursei în model de accesul clientului. În caz contrar, în cazul, de exemplu, ștergerea unui fișier, clientul ar putea continua să dețină un obiect care nu se mai află în model, cu problemele care decurg. Eclipse rezolvă această problemă folosind ceva numit manipula resursă. Mânerul acționează ca o cheie (cunoaște doar calea către resursă în spațiul de lucru) și controlează complet accesul la obiectul model intern, care stochează direct informații despre starea resursei. Acest design este o variație a modelului
Orez. Figura 2 ilustrează expresia Mâner/Corp așa cum este aplicată modelului de resurse. Interfața IResource reprezintă mânerul unei resurse și este un API, spre deosebire de clasa Resource, care implementează această interfață, și clasa ResourceInfo, care reprezintă corpul, care nu sunt API-uri. Subliniem că handle-ul cunoaște doar calea către resursă în raport cu rădăcina spațiului de lucru și nu conține un link către informații despre resurse. Obiectele de informații despre resurse formează așa-numitul „arbore de elemente”. Această structură de date este complet materializată în memorie. Pentru a găsi instanța de informații despre resurse corespunzătoare unui mâner, arborele de elemente este parcurs în funcție de calea stocată în acel mâner.
Orez. 2. IResource și ResourceInfo
După cum vom vedea mai târziu, designul de bază al modelului de resurse (l-am putea numi bazat pe mâner) este folosit în Eclipse și pentru alte modele. Deocamdată, să enumerăm câteva dintre proprietățile distinctive ale acestui design:
- Mânerul este un obiect de valoare. Obiectele de valoare sunt obiecte imuabile a căror egalitate nu se bazează pe identitate. Astfel de obiecte pot fi folosite în siguranță ca cheie în containerele hashed. Mai multe instanțe de handle pot face referire la aceeași resursă. Pentru a le compara, trebuie să utilizați metoda equals(Object).
- Mânerul definește comportamentul unei resurse, dar nu conține informații despre starea resursei (singurele date pe care le stochează sunt „cheia”, calea către resursă).
- Handle se poate referi la o resursă care nu există (fie o resursă care nu a fost încă creată, fie o resursă care a fost deja ștearsă). Existența unei resurse poate fi verificată folosind metoda IResource.exists().
- Unele operațiuni pot fi implementate doar pe baza informațiilor stocate în mâner în sine (așa-numitele operațiuni doar cu mâner). Exemple sunt IResource.getParent(), getFullPath(), etc. Resursa nu trebuie să existe pentru ca o astfel de operațiune să reușească. Operațiunile care necesită existența unei resurse pentru a reuși lansează o CoreException dacă resursa nu există.
Eclipse oferă un mecanism eficient pentru notificarea modificărilor resurselor spațiului de lucru (Figura 3). Resursele se pot modifica fie ca urmare a acțiunilor efectuate în cadrul IDE-ului Eclipse, fie ca urmare a sincronizării cu sistemul de fișiere. În ambele cazuri, clienților care se abonează la notificări li se oferă informații detaliate despre modificări sub formă de „delte de resurse”. O delta descrie schimbările între două stări ale unui (sub)arbore de resurse spațiu de lucru și este el însuși un arbore, fiecare nod descrie o modificare a unei resurse și conține o listă de delte la nivelul următor care descriu modificările aduse resurselor copil.
Orez. 3. IResourceChangeEvent și IResourceDelta
Mecanismul de notificare bazat pe delte de resurse are următoarele caracteristici:
- O singură modificare și multe modificări sunt descrise folosind aceeași structură, deoarece delta este construită folosind principiul compoziției recursive. Clienții abonați pot procesa notificările de modificare a resurselor utilizând coborârea recursivă printr-un arbore de delte.
- Delta conține informații complete despre modificările aduse resursei, inclusiv mișcarea acesteia și/sau modificări ale „markerilor” asociați cu aceasta (de exemplu, erorile de compilare sunt reprezentate ca markeri).
- Deoarece referințele la resurse sunt făcute prin intermediul mânerului, delta poate face referire în mod natural la o resursă la distanță.
După cum vom vedea în curând, principalele componente ale proiectării mecanismului de notificare a modificării modelului de resurse sunt relevante și pentru alte modele bazate pe mânere.
JDT Core
Modelul de resurse pentru spațiul de lucru Eclipse este un model fundamental independent de limbaj. Componenta JDT Core (plugin org.eclipse.jdt.core) oferă un API pentru navigarea și analizarea structurii spațiului de lucru din perspectivă Java, așa-numitul „model Java” (Model Java). Acest API este definit în termeni de elemente Java, spre deosebire de API-ul subiacent al modelului de resurse, care este definit în termeni de foldere și fișiere. Principalele interfețe ale arborelui de elemente Java sunt prezentate în Fig. 4.
Orez. 4. Elemente de model Java
Modelul Java folosește același limbaj de mâner/corp ca și modelul de resurse (Figura 5). IJavaElement este mânerul, iar JavaElementInfo joacă rolul de body. Interfața IJavaElement definește un protocol comun tuturor elementelor Java. Unele dintre metodele sale sunt doar pentru manere: getElementName(), getParent(), etc. Obiectul JavaElementInfo stochează starea elementului corespunzător: structura și atributele acestuia.
Orez. 5. IJavaElement și JavaElementInfo
Modelul Java are unele diferențe în implementarea designului de bază al mânerului/corpului în comparație cu modelul de resurse. După cum sa menționat mai sus, în modelul de resurse, arborele de elemente, ale cărui noduri sunt obiecte de informații despre resurse, este în întregime conținut în memorie. Dar modelul Java poate avea un număr semnificativ mai mare de elemente decât arborele de resurse, deoarece reprezintă și structura internă a fișierelor .java și .class: tipuri, câmpuri și metode.
Pentru a evita materializarea completă a întregului arbore de elemente în memorie, implementarea modelului Java utilizează un cache LRU de dimensiune limitată de informații despre element, unde cheia este mânerul IJavaElement. obiectele de informații despre elemente sunt create la cerere pe măsură ce se navighează în arborele de elemente. În acest caz, articolele utilizate cel mai puțin frecvent sunt evacuate din cache, iar consumul de memorie al modelului rămâne limitat la dimensiunea cache-ului specificată. Acesta este un alt avantaj al designului bazat pe mâner, care ascunde complet astfel de detalii de implementare din codul clientului.
Mecanismul de notificare a modificărilor la elementele Java este, în general, similar cu mecanismul de urmărire a modificărilor la resursele spațiului de lucru discutat mai sus. Un client care dorește să monitorizeze modificările în modelul Java se abonează la notificări, care sunt reprezentate ca un obiect ElementChangedEvent care conține un IJavaElementDelta (Figura 6).
Orez. 6. ElementChangedEvent și IJavaElementDelta
Modelul Java nu conține informații despre corpurile metodei sau rezoluția numelor, așa că pentru analiza detaliată a codului scris în Java, JDT Core oferă un model suplimentar (nebazat de mâner):
Deoarece arborii de sintaxă pot consuma o cantitate semnificativă de memorie, JDT memorează în cache un singur AST pentru editorul activ. Spre deosebire de modelul Java, AST este privit în mod obișnuit ca un model „intermediar”, „temporar” ai cărui membri nu ar trebui să fie referiți de către clienți în afara contextului operațiunii care a dus la crearea AST.
Cele trei modele enumerate (model Java, AST, legături) formează împreună baza pentru construirea de „instrumente de dezvoltare inteligente” în JDT, inclusiv un editor Java puternic cu diverse „ajutoare”, diverse acțiuni pentru procesarea codului sursă (inclusiv organizarea unei liste de import). nume și formatare în funcție de stilul personalizat), instrumente de căutare și refactorizare. În acest caz, modelul Java joacă un rol special, deoarece acesta este folosit ca bază pentru o reprezentare vizuală a structurii aplicației dezvoltate (de exemplu, în Explorer de pachete, Outline, Căutare, Ierarhie de apeluri și Ierarhie de tip).
Componentele Eclipse utilizate în 1C: Instrumente de dezvoltare a întreprinderii
În fig. Figura 7 prezintă componentele Eclipse care formează baza platformei tehnologice pentru 1C: Instrumente de dezvoltare a întreprinderii.
Orez. 7. Eclipse ca platformă pentru 1C: Instrumente de dezvoltare a întreprinderii
Platforma Eclipse asigură infrastructura de bază. Am analizat câteva aspecte ale acestei infrastructuri în secțiunea anterioară.
Ca orice instrument cu adevărat general, EMF este potrivit pentru rezolvarea unei game largi de probleme de modelare, dar unele clase de modele (de exemplu, modelele bazate pe mâner discutate mai sus) pot necesita instrumente de modelare mai specializate. A vorbi despre EMF este o sarcină ingrată, mai ales în limitele limitate ale unui articol, deoarece acesta este subiectul unei cărți separate și una destul de groasă. Să remarcăm doar că sistemul calitativ de generalizări care stă la baza CEM a permis nașterea unei game întregi de proiecte dedicate modelării, care sunt incluse în proiectul de nivel superior.
1C: Instrumentele de dezvoltare a întreprinderii utilizează în mod activ atât EMF în sine, cât și o serie de alte proiecte de modelare Eclipse. În special, Xtext este unul dintre bazele instrumentelor de dezvoltare pentru astfel de limbaje 1C: Enterprise, cum ar fi limbajul de programare încorporat și limbajul de interogare. O altă bază pentru aceste instrumente de dezvoltare este proiectul Eclipse Handly, despre care vom discuta mai detaliat (dintre componentele Eclipse enumerate, este încă cel mai puțin cunoscut).
Principiile arhitecturale de bază ale modelelor bazate pe mâner, cum ar fi idiomul mâner/corp, au fost discutate mai sus folosind modelul de resurse și modelul Java ca exemple. De asemenea, a remarcat că atât modelul de resurse, cât și modelul Java sunt baze importante pentru instrumentele de dezvoltare Java Eclipse (JDT). Și deoarece aproape toate proiectele *DT Eclipse au o arhitectură similară cu JDT, nu ar fi o mare exagerare să spunem că modelele bazate pe mâner stau la baza multor, dacă nu toate IDE-urile construite pe platforma Eclipse. De exemplu, Eclipse C/C++ Development Tooling (CDT) are un model C/C++ bazat pe mâner, care joacă același rol în arhitectura CDT ca și modelul Java în JDT.
Înainte de Handly, Eclipse nu oferea biblioteci specializate pentru construirea modelelor de limbaj bazate pe handle. Modelele care există în prezent au fost create în principal prin adaptarea directă a codului modelului Java (aka copy/paste), în cazurile în care permite Eclipse Public License (EPL). (Evident, aceasta nu este de obicei o problemă legală pentru, de exemplu, proiectele Eclipse în sine, dar nu pentru produsele cu sursă închisă.) Pe lângă hazardul inerent, această tehnică introduce probleme binecunoscute: duplicarea codului introdusă de atunci când se adaptează la erori, etc. Mai rău este că modelele rezultate rămân „lucruri în sine” și nu profită de potențialul de unificare. Dar izolarea conceptelor și protocoalelor comune pentru modelele de limbaj bazate pe mânere ar putea duce la crearea de componente reutilizabile pentru lucrul cu acestea, similar cu ceea ce s-a întâmplat în cazul EMF.
Nu este că Eclipse nu a înțeles aceste probleme. În 2005
Într-un anumit sens, proiectul Handly este conceput pentru a rezolva aproximativ aceleași probleme ca și EMF, dar pentru modele bazate pe mâner și în primul rând pentru cele de limbaj (adică, reprezentând elemente ale structurii unui limbaj de programare). Principalele obiective stabilite la proiectarea Handly sunt enumerate mai jos:
- Identificarea principalelor abstractizări ale domeniului subiectului.
- Reducerea efortului și îmbunătățirea calității implementării modelelor de limbaj bazate pe mânere prin reutilizarea codului.
- Furnizarea unui API unificat la nivel meta modelelor rezultate, făcând posibilă crearea de componente IDE comune care funcționează cu modele bazate pe mâner de limbaj.
- Flexibilitate și scalabilitate.
- Integrare cu Xtext (într-un strat separat).
Pentru a evidenția concepte și protocoale comune, au fost analizate implementările existente ale modelelor bazate pe mâner de limbaj. Principalele interfețe și implementările de bază furnizate de Handly sunt prezentate în Fig. 8.
Orez. 8. Interfețe comune și implementări de bază ale elementelor Handly
Interfața IElement reprezintă mânerul unui element și este comună elementelor tuturor modelelor bazate pe Handly. Clasa abstractă Element implementează mecanismul generalizat mâner/corp (Fig. 9).
Orez. 9. IElement și implementare generică de mâner/corp
În plus, Handly oferă un mecanism generalizat de notificare despre modificările elementelor modelului (Fig. 10). După cum puteți vedea, este similar cu mecanismele de notificare implementate în modelul de resurse și modelul Java și folosește IElementDelta pentru a oferi o reprezentare unificată a informațiilor despre modificarea elementelor.
Orez. 10. Interfețe generale și implementări de bază ale mecanismului de notificare Handly
Partea Handly discutată mai sus (Fig. 9 și 10) poate fi folosită pentru a reprezenta aproape orice model bazat pe mâner. Pentru a crea lingvistic modele, proiectul oferă funcționalități suplimentare - în special, interfețe comune și implementări de bază pentru elementele structurii textului sursă, așa-numitele elemente sursă (Fig. 8). Interfața ISourceFile reprezintă un fișier sursă, iar ISourceConstruct reprezintă un element din fișierul sursă. Clasele abstracte SourceFile și SourceConstruct implementează mecanisme generalizate pentru a sprijini lucrul cu fișierele sursă și elementele acestora, de exemplu, lucrul cu buffer-uri de text, legarea la coordonatele unui element din textul sursă, reconcilierea modelelor cu conținutul curent al unui buffer de copiere de lucru. , etc. Implementarea acestor mecanisme este de obicei destul de o provocare, iar Handly poate reduce semnificativ efortul de dezvoltare a modelelor de limbaj bazate pe manere, oferind implementări de bază de înaltă calitate.
În plus față de mecanismele de bază enumerate mai sus, Handly oferă o infrastructură pentru buffer-uri de text și instantanee, suport pentru integrarea cu editorii de cod sursă (inclusiv integrarea ieșită din cutie cu editorul Xtext), precum și câteva componente comune ale UI care lucrează cu editori de cod sursă.Modele manevrabile, cum ar fi cadrul de contur. Pentru a-și ilustra capacitățile, proiectul oferă mai multe exemple, inclusiv o implementare a modelului Java în Handly. (Comparativ cu implementarea completă a modelului Java în JDT, acest model este intenționat oarecum simplificat pentru o mai mare claritate.)
După cum sa menționat mai devreme, un accent major în timpul designului inițial al lui Handly și al dezvoltării ulterioare a fost și continuă să fie pe scalabilitate și flexibilitate.
În principiu, modelele bazate pe mâner se scalează destul de bine „prin proiect”. De exemplu, expresia mâner/corp vă permite să limitați cantitatea de memorie consumată de un model. Dar există și nuanțe. Astfel, la testarea Handly pentru scalabilitate, a fost descoperită o problemă în implementarea mecanismului de notificare - când au fost schimbate un număr mare de elemente, construirea deltelor a durat prea mult. S-a dovedit că aceeași problemă a fost prezentă în modelul JDT Java, din care a fost adaptat odată codul corespunzător. Am remediat eroarea în Handly și am pregătit un patch similar pentru JDT, care a fost primit cu recunoștință. Acesta este doar un exemplu în care introducerea Handly în implementările de model existente ar putea fi potențial utilă, deoarece în acest caz o astfel de eroare ar putea fi remediată într-un singur loc.
Pentru a face ca implementarea Handly în implementările de model existente să fie fezabilă din punct de vedere tehnic, biblioteca trebuie să aibă o flexibilitate semnificativă. Problema principală este menținerea compatibilității cu versiunea inversă a modelului API. Această problemă a fost rezolvată în
Flexibilitatea are și alte aspecte. De exemplu, Handly nu impune aproape nicio restricție asupra structurii modelului și poate fi folosit pentru a modela atât limbaje de uz general, cât și limbaje specifice domeniului. La construirea structurii fișierului sursă, Handly nu prescrie nicio formă specială de reprezentare AST și, în principiu, nici măcar nu necesită prezența unui AST în sine, asigurând astfel compatibilitatea cu aproape orice mecanism de analizare. În cele din urmă, Handly acceptă integrarea completă cu spațiul de lucru Eclipse, dar poate lucra și direct cu sistemele de fișiere datorită integrării sale cu
Versiune curentă
După cum sa menționat mai sus, unul dintre aceste produse este 1C: Instrumente de dezvoltare a întreprinderii, unde Handly este folosit de la bun început pentru a modela elemente ale structurii de nivel înalt a unor astfel de limbaje 1C:Enterprise, cum ar fi limbajul de programare încorporat și limbajul de interogare. . Un alt produs este mai puțin cunoscut publicului larg. Acest
Sperăm că după lansarea versiunii 1.0 cu garanția stabilității API și a părăsirii proiectului din starea de incubare, Handly va avea noi adoptatori. Între timp, proiectul continuă să testeze și să îmbunătățească în continuare API-ul, lansând două lansări „mare” pe an – în iunie (aceeași dată cu lansarea simultană a Eclipse) și decembrie, oferind un program previzibil pe care se pot baza utilizatorii. Putem adăuga, de asemenea, că „rata de erori” a proiectului rămâne la un nivel constant scăzut și Handly a lucrat în mod fiabil în produsele primilor adoptatori încă de la primele versiuni. Pentru a explora în continuare Eclipse Handly, puteți utiliza
Sursa: www.habr.com