probabilmente
In questo articolo, che è di natura panoramica, cercheremo di esaminare alcune delle nozioni di base dell'architettura Eclipse come piattaforma per la creazione di strumenti di sviluppo integrati e di dare un'idea iniziale dei componenti Eclipse che costituiscono il fondamento della tecnologia. piattaforma per il “nuovo Configuratore” 1C: Enterprise.
Introduzione all'architettura Eclipse
Diamo prima un'occhiata ad alcuni aspetti generali dell'architettura Eclipse utilizzando l'esempio
Innanzitutto va notato che Eclipse è caratterizzato da una stratificazione architetturale abbastanza chiara, con la separazione delle funzionalità indipendenti dal linguaggio da quelle progettate per supportare linguaggi di programmazione specifici, e la separazione dei componenti “core” indipendenti dall’interfaccia utente dai componenti associati con interfaccia utente di supporto.
Pertanto, la piattaforma Eclipse definisce un'infrastruttura comune, indipendente dal linguaggio, e gli strumenti di sviluppo Java aggiungono a Eclipse un IDE Java completo di funzionalità. Sia la piattaforma Eclipse che JDT sono costituiti da diversi componenti, ciascuno dei quali appartiene a un "core" indipendente dall'interfaccia utente o a un livello dell'interfaccia utente (Figura 1).
Riso. 1. Piattaforma Eclipse e JDT
Elenchiamo i componenti principali della Piattaforma Eclipse:
- Runtime — Definisce l'infrastruttura del plugin. Eclipse è caratterizzato da un'architettura modulare. Essenzialmente, Eclipse è una raccolta di "punti di estensione" ed "estensioni".
- Area di lavoro — Gestisce uno o più progetti. Un progetto è costituito da cartelle e file mappati direttamente al file system.
- Kit di strumenti widget standard (SWT) - Fornisce elementi di base dell'interfaccia utente integrati con il sistema operativo.
- JFaccia — Fornisce una serie di framework UI basati su SWT.
- banco di lavoro — Definisce il paradigma dell'interfaccia utente di Eclipse: editor, visualizzazioni, prospettive.
Va detto che la piattaforma Eclipse fornisce anche molti altri componenti utili per creare strumenti di sviluppo integrati, tra cui Debug, Confronta, Ricerca e Team. Una menzione speciale dovrebbe essere fatta a JFace Text, la base per la creazione di "editor intelligenti" del codice sorgente. Sfortunatamente, anche un esame superficiale di questi componenti, così come dei componenti del livello UI, non è possibile nell'ambito di questo articolo, quindi nel resto di questa sezione ci limiteremo a una panoramica dei principali componenti "core" di la piattaforma Eclipse e JDT.
Runtime principale
L'infrastruttura del plugin Eclipse è basata su
Area di lavoro principale
Quasi tutti gli ambienti di sviluppo integrati basati sulla piattaforma Eclipse funzionano con l'area di lavoro Eclipse. È l'area di lavoro che solitamente contiene il codice sorgente dell'applicazione sviluppata nell'IDE. L'area di lavoro è mappata direttamente al file system ed è composta da progetti che contengono cartelle e file. Questi progetti, cartelle e file vengono chiamati le risorse spazio di lavoro. L'implementazione dello spazio di lavoro in Eclipse funge da cache rispetto al file system, il che consente di accelerare notevolmente l'attraversamento dell'albero delle risorse. Inoltre, Workspace fornisce una serie di servizi aggiuntivi, tra cui
Il componente Core Resources (plugin org.eclipse.core.resources) è responsabile del supporto dello spazio di lavoro e delle sue risorse. In particolare, questo componente fornisce l'accesso programmatico all'area di lavoro nel modulo modelli di risorse. Per lavorare in modo efficace con questo modello, i clienti necessitano di un modo semplice per presentare un collegamento a una risorsa. In questo caso sarebbe auspicabile nascondere all'accesso del client l'oggetto che memorizza direttamente lo stato della risorsa nel modello. Altrimenti, nel caso, ad esempio, di cancellazione di un file, il client potrebbe continuare a trattenere un oggetto che non è più presente nel modello, con i conseguenti problemi. Eclipse risolve questo problema usando qualcosa chiamato maniglia risorsa. Handle funge da chiave (conosce solo il percorso della risorsa nell'area di lavoro) e controlla completamente l'accesso all'oggetto del modello interno, che memorizza direttamente le informazioni sullo stato della risorsa. Questo disegno è una variazione del modello
Riso. La Figura 2 illustra il linguaggio Maniglia/Corpo applicato al modello di risorsa. L'interfaccia IResource rappresenta l'handle di una risorsa ed è un'API, a differenza della classe Resource, che implementa questa interfaccia, e della classe ResourceInfo, che rappresenta il corpo, che non sono API. Sottolineiamo che handle conosce solo il percorso della risorsa relativo alla radice dell'area di lavoro e non contiene un collegamento alle informazioni sulla risorsa. Gli oggetti informazioni sulle risorse formano un cosiddetto “albero degli elementi”. Questa struttura dati è completamente materializzata in memoria. Per trovare l'istanza delle informazioni sulla risorsa corrispondente a un handle, l'albero degli elementi viene attraversato in base al percorso memorizzato in quell'handle.
Riso. 2. IResource e ResourceInfo
Come vedremo più avanti, il design di base del modello risorsa (potremmo chiamarlo basato su handle) viene utilizzato in Eclipse anche per altri modelli. Per ora, elenchiamo alcune delle proprietà distintive di questo design:
- Handle è un oggetto valore. Gli oggetti valore sono oggetti immutabili la cui uguaglianza non è basata sull'identità. Tali oggetti possono essere tranquillamente utilizzati come chiave nei contenitori con hash. Più istanze di handle possono fare riferimento alla stessa risorsa. Per confrontarli è necessario utilizzare il metodo equals(Object).
- Handle definisce il comportamento di una risorsa, ma non contiene informazioni sullo stato della risorsa (gli unici dati che memorizza sono la "chiave", il percorso della risorsa).
- L'handle può fare riferimento a una risorsa che non esiste (una risorsa che non è stata ancora creata o una risorsa che è già stata eliminata). L'esistenza di una risorsa può essere verificata utilizzando il metodo IResource.exists().
- Alcune operazioni possono essere implementate basandosi esclusivamente sulle informazioni memorizzate nell'handle stesso (le cosiddette operazioni handle-only). Gli esempi sono IResource.getParent(), getFullPath(), ecc. Non è necessario che la risorsa esista affinché tale operazione abbia esito positivo. Le operazioni che richiedono l'esistenza di una risorsa per avere successo lanciano una CoreException se la risorsa non esiste.
Eclipse fornisce un meccanismo efficiente per notificare le modifiche alle risorse dell'area di lavoro (Figura 3). Le risorse possono cambiare come risultato di azioni eseguite all'interno dell'IDE Eclipse stesso o come risultato della sincronizzazione con il file system. In entrambi i casi, ai clienti che si iscrivono alle notifiche vengono fornite informazioni dettagliate sui cambiamenti sotto forma di “delta risorse”. Un delta descrive le modifiche tra due stati di un (sotto)albero di risorse dell'area di lavoro ed è esso stesso un albero, ciascun nodo del quale descrive una modifica a una risorsa e contiene un elenco di delta al livello successivo che descrivono le modifiche alle risorse figlio.
Riso. 3. IResourceChangeEvent e IResourceDelta
Il meccanismo di notifica basato sui delta risorse ha le seguenti caratteristiche:
- Un singolo cambiamento e molti cambiamenti vengono descritti utilizzando la stessa struttura, poiché il delta è costruito utilizzando il principio della composizione ricorsiva. I client dell'abbonato possono elaborare le notifiche di modifica delle risorse utilizzando la discesa ricorsiva attraverso un albero di delta.
- Il delta contiene informazioni complete sui cambiamenti apportati alla risorsa, incluso il suo movimento e/o cambiamenti nei “marcatori” ad essa associati (ad esempio, errori di compilazione sono rappresentati come marcatori).
- Poiché i riferimenti alle risorse vengono effettuati tramite l'handle, delta può naturalmente fare riferimento a una risorsa remota.
Come vedremo presto, i componenti principali della progettazione del meccanismo di notifica delle modifiche al modello di risorsa sono rilevanti anche per altri modelli basati su handle.
JDT Nucleo
Il modello di risorse dell'area di lavoro Eclipse è un modello fondamentale indipendente dal linguaggio. Il componente JDT Core (plugin org.eclipse.jdt.core) fornisce un'API per la navigazione e l'analisi della struttura dello spazio di lavoro da una prospettiva Java, il cosiddetto "modello Java" (Modello Java). Questa API è definita in termini di elementi Java, al contrario dell'API del modello di risorsa sottostante, che è definita in termini di cartelle e file. Le principali interfacce dell'albero degli elementi Java sono mostrate in Fig. 4.
Riso. 4. Elementi del modello Java
Il modello Java utilizza lo stesso linguaggio handle/corpo del modello di risorsa (Figura 5). IJavaElement è l'handle e JavaElementInfo svolge il ruolo del corpo. L'interfaccia IJavaElement definisce un protocollo comune a tutti gli elementi Java. Alcuni dei suoi metodi sono solo handle: getElementName(), getParent(), ecc. L'oggetto JavaElementInfo memorizza lo stato dell'elemento corrispondente: la sua struttura e i suoi attributi.
Riso. 5. IJavaElement e JavaElementInfo
Il modello Java presenta alcune differenze nell'implementazione del design base della maniglia/corpo rispetto al modello risorsa. Come notato sopra, nel modello risorsa, l'albero degli elementi, i cui nodi sono oggetti informazioni sulla risorsa, è interamente contenuto in memoria. Ma il modello Java può avere un numero di elementi significativamente maggiore rispetto all'albero delle risorse, perché rappresenta anche la struttura interna dei file .java e .class: tipi, campi e metodi.
Per evitare di materializzare completamente l'intero albero di elementi in memoria, l'implementazione del modello Java utilizza una cache LRU di dimensioni limitate di informazioni sugli elementi, dove la chiave è handle IJavaElement. gli oggetti informazioni sugli elementi vengono creati su richiesta mentre si naviga nell'albero degli elementi. In questo caso, gli elementi utilizzati meno frequentemente vengono rimossi dalla cache e il consumo di memoria del modello rimane limitato alla dimensione della cache specificata. Questo è un altro vantaggio della progettazione basata su handle, che nasconde completamente tali dettagli di implementazione dal codice client.
Il meccanismo per notificare le modifiche agli elementi Java è in generale simile al meccanismo per tenere traccia delle modifiche alle risorse dell'area di lavoro discusso in precedenza. Un client che desidera monitorare le modifiche nel modello Java si iscrive alle notifiche, che sono rappresentate come un oggetto ElementChangedEvent che contiene un IJavaElementDelta (Figura 6).
Riso. 6. ElementChangedEvent e IJavaElementDelta
Il modello Java non contiene informazioni sui corpi dei metodi o sulla risoluzione dei nomi, quindi per un'analisi dettagliata del codice scritto in Java, JDT Core fornisce un modello aggiuntivo (non basato su handle):
Poiché gli alberi della sintassi possono consumare una quantità significativa di memoria, JDT memorizza nella cache solo un AST per l'editor attivo. A differenza del modello Java, l'AST è generalmente visto come un modello "intermedio" e "temporaneo" i cui membri non dovrebbero essere considerati referenziati dai client al di fuori del contesto dell'operazione che ha portato alla creazione dell'AST.
I tre modelli elencati (modello Java, AST, collegamenti) insieme costituiscono la base per la creazione di "strumenti di sviluppo intelligenti" in JDT, incluso un potente editor Java con vari "aiutanti", varie azioni per l'elaborazione del codice sorgente (inclusa l'organizzazione di un elenco di import nomi e formattazione secondo lo stile personalizzato), strumenti di ricerca e refactoring. In questo caso, il modello Java gioca un ruolo speciale, poiché viene utilizzato come base per una rappresentazione visiva della struttura dell'applicazione in fase di sviluppo (ad esempio, in Package Explorer, Outline, Search, Call Hierarchy e Gerarchia dei tipi).
Componenti Eclipse utilizzati in 1C:Enterprise Developments Tools
Nella fig. La Figura 7 mostra i componenti Eclipse che costituiscono la base della piattaforma tecnologica per 1C:Enterprise Development Tools.
Riso. 7. Eclipse come piattaforma per 1C: strumenti di sviluppo aziendale
Piattaforma Eclipse fornisce le infrastrutture di base. Abbiamo esaminato alcuni aspetti di questa infrastruttura nella sezione precedente.
Come ogni strumento veramente generico, EMF è adatto a risolvere un'ampia gamma di problemi di modellazione, ma alcune classi di modelli (ad esempio, i modelli basati su handle discussi sopra) potrebbero richiedere strumenti di modellazione più specializzati. Parlare di campi elettromagnetici è un compito ingrato, soprattutto entro i confini limitati di un articolo, poiché questo è oggetto di un libro a parte, e piuttosto voluminoso. Notiamo solo che il sistema di generalizzazioni di alta qualità alla base dell'EMF ha consentito la nascita di tutta una serie di progetti dedicati alla modellizzazione, che sono inclusi nel progetto di primo livello
1C:Enterprise Development Tools utilizza attivamente sia EMF stesso che una serie di altri progetti di modellazione Eclipse. In particolare, Xtext è uno dei fondamenti degli strumenti di sviluppo per linguaggi 1C:Enterprise come il linguaggio di programmazione integrato e il linguaggio di query. Un'altra base per questi strumenti di sviluppo è il progetto Eclipse Handly, di cui parleremo più in dettaglio (tra i componenti Eclipse elencati, è ancora il meno conosciuto).
I principi architetturali di base dei modelli basati su handle, come l'idioma handle/body, sono stati discussi in precedenza utilizzando il modello risorsa e il modello Java come esempi. È stato inoltre osservato che sia il modello delle risorse che il modello Java costituiscono basi importanti per gli strumenti di sviluppo Java di Eclipse (JDT). E poiché quasi tutti i progetti *DT Eclipse hanno un'architettura simile a JDT, non sarebbe un'esagerazione affermare che i modelli basati su handle sono alla base di molti, se non di tutti, gli IDE costruiti sulla piattaforma Eclipse. Ad esempio, Eclipse C/C++ Development Tooling (CDT) dispone di un modello C/C++ basato su handle che svolge lo stesso ruolo nell'architettura CDT del modello Java in JDT.
Prima di Handly, Eclipse non offriva librerie specializzate per la creazione di modelli linguistici basati su handle. I modelli attualmente esistenti sono stati creati principalmente adattando direttamente il codice del modello Java (noto anche come copia/incolla), nei casi in cui lo consente Licenza pubblica Eclipse (EPL). (Ovviamente, questo di solito non è un problema legale, ad esempio, per i progetti Eclipse in sé, ma non per i prodotti closed source.) Oltre alla sua intrinseca casualità, questa tecnica introduce problemi ben noti: duplicazione del codice introdotta quando ci si adatta agli errori, eccetera. Quel che è peggio è che i modelli risultanti rimangono “cose a sé” e non sfruttano il potenziale di unificazione. Ma isolare concetti e protocolli comuni per modelli linguistici basati su handle potrebbe portare alla creazione di componenti riutilizzabili per lavorare con essi, in modo simile a quanto accaduto nel caso di EMF.
Non è che Eclipse non capisse questi problemi. Nel 2005
In un certo senso, il progetto Handly è progettato per risolvere approssimativamente gli stessi problemi di EMF, ma per modelli basati su handle e, principalmente, linguistici (ovvero, che rappresentano elementi della struttura di alcuni linguaggi di programmazione). Gli obiettivi principali fissati durante la progettazione di Handly sono elencati di seguito:
- Individuazione delle principali astrazioni dell'area disciplinare.
- Riduzione degli sforzi e miglioramento della qualità dell'implementazione dei modelli linguistici basati su handle attraverso il riutilizzo del codice.
- Fornire un'API unificata a meta livello ai modelli risultanti, consentendo di creare componenti IDE comuni che funzionano con modelli basati su handle di linguaggio.
- Flessibilità e scalabilità.
- Integrazione con Xtext (in un livello separato).
Per evidenziare concetti e protocolli comuni, sono state analizzate le implementazioni esistenti di modelli basati su handle del linguaggio. Le principali interfacce e implementazioni di base fornite da Handly sono mostrate in Fig. 8.
Riso. 8. Interfacce comuni e implementazioni di base degli elementi Handly
L'interfaccia IElement rappresenta l'handle di un elemento ed è comune agli elementi di tutti i modelli basati su Handly. La classe astratta Element implementa il meccanismo generalizzato maniglia/corpo (Fig. 9).
Riso. 9. IElement e implementazione generica di handle/corpo
Inoltre, Handly fornisce un meccanismo generalizzato per notificare i cambiamenti negli elementi del modello (Fig. 10). Come puoi vedere, è sostanzialmente simile ai meccanismi di notifica implementati nel modello di risorsa e nel modello Java e utilizza IElementDelta per fornire una rappresentazione unificata delle informazioni sulla modifica degli elementi.
Riso. 10. Interfacce generali e implementazioni di base del meccanismo di notifica Handly
La parte Handly discussa sopra (Fig. 9 e 10) può essere utilizzata per rappresentare quasi tutti i modelli basati su maniglia. Per creare linguistico modelli, il progetto offre funzionalità aggiuntive - in particolare interfacce comuni e implementazioni di base per elementi della struttura del testo sorgente, i cosiddetti elementi di origine (Fig. 8). L'interfaccia ISourceFile rappresenta un file di origine e ISourceConstruct rappresenta un elemento all'interno del file di origine. Le classi astratte SourceFile e SourceConstruct implementano meccanismi generalizzati per supportare il lavoro con i file sorgente e i loro elementi, ad esempio, lavorando con buffer di testo, legandosi alle coordinate di un elemento nel testo sorgente, riconciliando i modelli con il contenuto corrente di un buffer di copia di lavoro , eccetera. L'implementazione di questi meccanismi è solitamente una vera sfida e Handly può ridurre significativamente lo sforzo di sviluppare modelli linguistici basati su handle fornendo implementazioni di base di alta qualità.
Oltre ai meccanismi principali elencati sopra, Handly fornisce un'infrastruttura per buffer di testo e istantanee, supporto per l'integrazione con editor di codice sorgente (inclusa l'integrazione pronta all'uso con l'editor Xtext), nonché alcuni componenti comuni dell'interfaccia utente che lavorare con gli editor del codice sorgente. Gestire modelli come il framework di contorno. Per illustrare le sue capacità, il progetto fornisce diversi esempi, inclusa un'implementazione del modello Java in Handly. (Rispetto all'implementazione completa del modello Java in JDT, questo modello è intenzionalmente un po' semplificato per una maggiore chiarezza.)
Come notato in precedenza, l'attenzione principale durante la progettazione iniziale di Handly e il successivo sviluppo è stata e continua ad essere rivolta alla scalabilità e alla flessibilità.
In linea di principio, i modelli basati su maniglie si adattano abbastanza bene “by design”. Ad esempio, il linguaggio handle/body consente di limitare la quantità di memoria consumata da un modello. Ma ci sono anche delle sfumature. Pertanto, durante il test di scalabilità di Handly, è stato scoperto un problema nell'implementazione del meccanismo di notifica: quando un numero elevato di elementi veniva modificato, la costruzione dei delta richiedeva troppo tempo. Si è scoperto che lo stesso problema era presente nel modello Java JDT, da cui una volta è stato adattato il codice corrispondente. Abbiamo corretto il bug in Handly e preparato una patch simile per JDT, che è stata accolta con gratitudine. Questo è solo un esempio in cui l'introduzione di Handly nelle implementazioni di modelli esistenti potrebbe essere potenzialmente utile, perché in questo caso un bug di questo tipo potrebbe essere corretto in un solo posto.
Per rendere tecnicamente fattibile l'implementazione di Handly nelle implementazioni di modelli esistenti, la biblioteca deve avere una notevole flessibilità. Il problema principale è mantenere la compatibilità con le versioni precedenti del modello API. Questo problema è stato risolto nel
La flessibilità ha anche altri aspetti. Ad esempio, Handly non impone quasi alcuna restrizione sulla struttura del modello e può essere utilizzato per modellare sia linguaggi generici che specifici del dominio. Nella costruzione della struttura del file sorgente, Handly non prescrive alcuna forma particolare di rappresentazione AST e, in linea di principio, non richiede nemmeno la presenza di un AST stesso, garantendo così la compatibilità con quasi tutti i meccanismi di parsing. Infine, Handly supporta la piena integrazione con lo spazio di lavoro Eclipse, ma può anche funzionare direttamente con i file system grazie alla sua integrazione con
Versione corrente
Come notato sopra, uno di questi prodotti è 1C:Enterprise Development Tools, dove Handly viene utilizzato fin dall'inizio per modellare elementi della struttura di alto livello di tali linguaggi 1C:Enterprise come il linguaggio di programmazione integrato e il linguaggio di query . Un altro prodotto è meno conosciuto dal grande pubblico. Questo
Ci auguriamo che dopo il rilascio della versione 1.0 con garanzia di stabilità API e l'uscita del progetto dallo stato di incubazione, Handly abbia nuovi adottanti. Nel frattempo, il progetto continua a testare e migliorare ulteriormente l'API, rilasciando due versioni "principali" all'anno: a giugno (la stessa data del rilascio simultaneo di Eclipse) e dicembre, fornendo un programma prevedibile su cui gli adottanti possono fare affidamento. Possiamo anche aggiungere che il “bug rate” del progetto rimane a un livello costantemente basso e Handly ha lavorato in modo affidabile nei prodotti degli early adopter sin dalle primissime versioni. Per esplorare ulteriormente Eclipse Handly, puoi utilizzare
Fonte: habr.com