Provavelmente
Neste artigo, que é de natureza geral, tentaremos examinar alguns dos fundamentos da arquitetura Eclipse como uma plataforma para construir ferramentas de desenvolvimento integradas e dar uma ideia inicial dos componentes Eclipse que formam a base da tecnologia plataforma para o “novo Configurador” 1C:Enterprise.
Introdução à Arquitetura Eclipse
Vejamos primeiro alguns aspectos gerais da arquitetura Eclipse usando o exemplo
Em primeiro lugar, deve-se notar que o Eclipse é caracterizado por uma camada arquitetural bastante clara, com a separação da funcionalidade independente da linguagem da funcionalidade projetada para suportar linguagens de programação específicas, e a separação dos componentes “principais” independentes da UI dos componentes associados. com interface de usuário de suporte.
Assim, a plataforma Eclipse define uma infraestrutura comum e independente de linguagem, e as ferramentas de desenvolvimento Java adicionam um IDE Java completo ao Eclipse. Tanto a plataforma Eclipse quanto o JDT consistem em vários componentes, cada um dos quais pertence a um “núcleo” independente da UI ou a uma camada de UI (Figura 1).
Arroz. 1. Plataforma Eclipse e JDT
Vamos listar os principais componentes da Plataforma Eclipse:
- Runtime — Define a infraestrutura do plugin. Eclipse é caracterizado por uma arquitetura modular. Essencialmente, o Eclipse é uma coleção de “pontos de extensão” e “extensões”.
- Área de trabalho — Gerencia um ou mais projetos. Um projeto consiste em pastas e arquivos mapeados diretamente para o sistema de arquivos.
- Kit de ferramentas de widget padrão (SWT) - Fornece elementos básicos de interface de usuário integrados ao sistema operacional.
- JFaceName — Fornece uma série de estruturas de UI construídas sobre SWT.
- Workbench — Define o paradigma Eclipse UI: editores, visualizações, perspectivas.
Deve-se dizer que a plataforma Eclipse também fornece muitos outros componentes úteis para a construção de ferramentas de desenvolvimento integradas, incluindo Debug, Compare, Search e Team. Menção especial deve ser feita ao JFace Text - a base para a construção de “editores inteligentes” de código-fonte. Infelizmente, mesmo um exame superficial desses componentes, bem como dos componentes da camada UI, não é possível dentro do escopo deste artigo, portanto, no restante desta seção nos limitaremos a uma visão geral dos principais componentes “principais” do a plataforma Eclipse e JDT.
Tempo de execução principal
A infraestrutura do plugin Eclipse é baseada em
Espaço de trabalho principal
Quase qualquer ambiente de desenvolvimento integrado construído sobre a Plataforma Eclipse funciona com o espaço de trabalho Eclipse. É o espaço de trabalho que normalmente contém o código-fonte da aplicação desenvolvida no IDE. O espaço de trabalho é mapeado diretamente para o sistema de arquivos e consiste em projetos que contêm pastas e arquivos. Esses projetos, pastas e arquivos são chamados Recursos área de trabalho. A implementação do espaço de trabalho no Eclipse serve como cache em relação ao sistema de arquivos, o que permite acelerar significativamente a travessia da árvore de recursos. Além disso, o espaço de trabalho oferece vários serviços adicionais, incluindo
O componente Core Resources (plugin org.eclipse.core.resources) é responsável por dar suporte ao espaço de trabalho e seus recursos. Em particular, este componente fornece acesso programático ao espaço de trabalho no formato modelos de recursos. Para trabalhar eficazmente com este modelo, os clientes precisam de uma forma simples de apresentar um link para um recurso. Nesse caso, seria desejável ocultar do acesso do cliente o objeto que armazena diretamente o estado do recurso no modelo. Caso contrário, no caso de, por exemplo, excluir um arquivo, o cliente poderá continuar retendo um objeto que não está mais no modelo, com os problemas decorrentes. Eclipse resolve esse problema usando algo chamado manipular recurso. Handle atua como uma chave (só conhece o caminho para o recurso no espaço de trabalho) e controla completamente o acesso ao objeto do modelo interno, que armazena diretamente informações sobre o estado do recurso. Este design é uma variação do padrão
Arroz. A Figura 2 ilustra o idioma Handle/Body aplicado ao modelo de recursos. A interface IResource representa o identificador de um recurso e é uma API, ao contrário da classe Resource, que implementa essa interface, e da classe ResourceInfo, que representa o corpo, que não são APIs. Enfatizamos que o identificador conhece apenas o caminho para o recurso relativo à raiz do espaço de trabalho e não contém um link para informações do recurso. Os objetos de informações de recursos formam a chamada “árvore de elementos”. Esta estrutura de dados é totalmente materializada na memória. Para encontrar a instância de informações do recurso correspondente a um identificador, a árvore de elementos é percorrida de acordo com o caminho armazenado nesse identificador.
Arroz. 2. IResource e ResourceInfo
Como veremos mais adiante, o design básico do modelo de recursos (podemos chamá-lo de baseado em identificador) também é usado no Eclipse para outros modelos. Por enquanto, vamos listar algumas das propriedades distintivas deste design:
- Handle é um objeto de valor. Objetos de valor são objetos imutáveis cuja igualdade não é baseada na identidade. Esses objetos podem ser usados com segurança como chave em contêineres com hash. Várias instâncias de handle podem fazer referência ao mesmo recurso. Para compará-los, você precisa usar o método equals(Object).
- Handle define o comportamento de um recurso, mas não contém informações sobre o estado do recurso (os únicos dados que armazena são a "chave", o caminho para o recurso).
- Handle pode se referir a um recurso que não existe (um recurso que ainda não foi criado ou um recurso que já foi excluído). A existência de um recurso pode ser verificada usando o método IResource.exists().
- Algumas operações podem ser implementadas com base apenas nas informações armazenadas no próprio identificador (as chamadas operações somente de identificador). Exemplos são IResource.getParent(), getFullPath(), etc. O recurso não precisa existir para que tal operação seja bem-sucedida. As operações que exigem a existência de um recurso para serem bem-sucedidas geram uma CoreException se o recurso não existir.
O Eclipse fornece um mecanismo eficiente para notificar alterações nos recursos do espaço de trabalho (Figura 3). Os recursos podem mudar como resultado de ações executadas no próprio Eclipse IDE ou como resultado da sincronização com o sistema de arquivos. Em ambos os casos, os clientes que assinam notificações recebem informações detalhadas sobre as alterações na forma de “deltas de recursos”. Um delta descreve alterações entre dois estados de uma (sub)árvore de recursos do espaço de trabalho e é ele próprio uma árvore, cada nó descreve uma alteração em um recurso e contém uma lista de deltas no próximo nível que descreve alterações em recursos filho.
Arroz. 3. IResourceChangeEvent e IResourceDelta
O mecanismo de notificação baseado em deltas de recursos possui as seguintes características:
- Uma única mudança e muitas mudanças são descritas usando a mesma estrutura, já que o delta é construído usando o princípio da composição recursiva. Os clientes assinantes podem processar notificações de alteração de recursos usando descida recursiva por meio de uma árvore de deltas.
- O delta contém informações completas sobre alterações no recurso, incluindo sua movimentação e/ou alterações nos “marcadores” associados a ele (por exemplo, erros de compilação são representados como marcadores).
- Como as referências de recursos são feitas por meio do identificador, o delta pode naturalmente fazer referência a um recurso remoto.
Como veremos em breve, os principais componentes do design do mecanismo de notificação de alterações do modelo de recursos também são relevantes para outros modelos baseados em identificadores.
Núcleo JDT
O modelo de recursos do espaço de trabalho Eclipse é um modelo independente de linguagem fundamental. O componente JDT Core (plugin org.eclipse.jdt.core) fornece uma API para navegar e analisar a estrutura do espaço de trabalho a partir de uma perspectiva Java, o chamado “modelo Java” (Modelo Java). Esta API é definida em termos de elementos Java, em oposição à API do modelo de recurso subjacente, que é definida em termos de pastas e arquivos. As principais interfaces da árvore de elementos Java são mostradas na Fig. 4.
Arroz. 4. Elementos do modelo Java
O modelo Java usa o mesmo idioma de identificador/corpo que o modelo de recursos (Figura 5). IJavaElement é o identificador e JavaElementInfo desempenha o papel de corpo. A interface IJavaElement define um protocolo comum a todos os elementos Java. Alguns de seus métodos são somente manipuladores: getElementName(), getParent(), etc. O objeto JavaElementInfo armazena o estado do elemento correspondente: sua estrutura e atributos.
Arroz. 5. IJavaElement e JavaElementInfo
O modelo Java tem algumas diferenças na implementação do design básico de identificador/corpo em comparação com o modelo de recursos. Conforme observado acima, no modelo de recursos, a árvore de elementos, cujos nós são objetos de informações de recursos, está inteiramente contida na memória. Mas o modelo Java pode ter um número significativamente maior de elementos do que a árvore de recursos, porque também representa a estrutura interna dos arquivos .java e .class: tipos, campos e métodos.
Para evitar a materialização completa de toda a árvore de elementos na memória, a implementação do modelo Java usa um cache LRU de tamanho limitado de informações do elemento, onde a chave é o identificador IJavaElement. objetos de informações de elementos são criados sob demanda à medida que a árvore de elementos é navegada. Nesse caso, os itens usados com menos frequência são removidos do cache e o consumo de memória do modelo permanece limitado ao tamanho de cache especificado. Esta é outra vantagem do design baseado em identificador, que oculta completamente esses detalhes de implementação do código do cliente.
O mecanismo para notificar alterações em elementos Java é, em geral, semelhante ao mecanismo para rastrear alterações em recursos do espaço de trabalho discutido acima. Um cliente que deseja monitorar alterações no modelo Java assina notificações, que são representadas como um objeto ElementChangedEvent que contém um IJavaElementDelta (Figura 6).
Arroz. 6. ElementChangedEvent e IJavaElementDelta
O modelo Java não contém informações sobre corpos de métodos ou resolução de nomes, portanto, para análise detalhada do código escrito em Java, o JDT Core fornece um modelo adicional (não baseado em identificador):
Como as árvores de sintaxe podem consumir uma quantidade significativa de memória, o JDT armazena em cache apenas um AST para o editor ativo. Ao contrário do modelo Java, o AST é normalmente visto como um modelo “intermediário”, “temporário”, cujos membros não devem ser referenciados por clientes fora do contexto da operação que levou à criação do AST.
Os três modelos listados (modelo Java, AST, ligações) juntos formam a base para a construção de “ferramentas de desenvolvimento inteligentes” em JDT, incluindo um poderoso editor Java com vários “ajudantes”, várias ações para processamento de código-fonte (incluindo a organização de uma lista de importação nomes e formatação de acordo com o estilo customizado), ferramentas de busca e refatoração. Neste caso, o modelo Java desempenha um papel especial, pois é ele que serve de base para uma representação visual da estrutura da aplicação que está sendo desenvolvida (por exemplo, em Package Explorer, Outline, Search, Call Hierarchy e Tipo Hierarquia).
Componentes Eclipse usados em ferramentas de desenvolvimento 1C:Enterprise
Na Fig. A Figura 7 mostra os componentes do Eclipse que formam a base da plataforma tecnológica para 1C:Enterprise Development Tools.
Arroz. 7. Eclipse como plataforma para ferramentas de desenvolvimento 1C:Enterprise
Plataforma Eclipse fornece infraestrutura básica. Vimos alguns aspectos dessa infraestrutura na seção anterior.
Como qualquer ferramenta verdadeiramente de uso geral, o EMF é adequado para resolver uma ampla gama de problemas de modelagem, mas algumas classes de modelos (por exemplo, os modelos baseados em alças discutidos acima) podem exigir ferramentas de modelagem mais especializadas. Falar sobre CEM é uma tarefa ingrata, especialmente dentro dos limites limitados de um artigo, uma vez que este é o assunto de um livro separado, e bastante denso. Observemos apenas que o sistema de generalizações de alta qualidade subjacente ao EMF permitiu o nascimento de toda uma gama de projetos dedicados à modelagem, que estão incluídos no projeto de nível superior
1C:Enterprise Development Tools usa ativamente o próprio EMF e vários outros projetos de modelagem Eclipse. Em particular, o Xtext é uma das bases das ferramentas de desenvolvimento para linguagens 1C:Enterprise, como a linguagem de programação integrada e a linguagem de consulta. Outra base para essas ferramentas de desenvolvimento é o projeto Eclipse Handly, que discutiremos com mais detalhes (dos componentes do Eclipse listados, ainda é o menos conhecido).
Os princípios arquitetônicos básicos de modelos baseados em identificador, como o idioma identificador/corpo, foram discutidos acima usando o modelo de recursos e o modelo Java como exemplos. Ele também observou que tanto o modelo de recursos quanto o modelo Java são bases importantes para as ferramentas de desenvolvimento Java (JDT) Eclipse. E como quase todos os projetos *DT Eclipse têm uma arquitetura semelhante à JDT, não seria um grande exagero dizer que os modelos baseados em manipuladores são a base de muitos, se não de todos, IDEs construídos sobre a plataforma Eclipse. Por exemplo, o Eclipse C/C++ Development Tooling (CDT) possui um modelo C/C++ baseado em identificador que desempenha a mesma função na arquitetura CDT que o modelo Java desempenha no JDT.
Antes do Handly, o Eclipse não oferecia bibliotecas especializadas para construir modelos de linguagem baseados em identificadores. Os modelos que existem atualmente foram criados principalmente pela adaptação direta do código do modelo Java (também conhecido como copiar/colar), nos casos em que permite Licença Pública Eclipse (EPL). (Obviamente, isso geralmente não é uma questão legal para, digamos, projetos Eclipse em si, mas não para produtos de código fechado.) Além de sua natureza aleatória, essa técnica introduz problemas bem conhecidos: duplicação de código introduzida ao se adaptar a erros, etc. O pior é que os modelos resultantes continuam a ser “coisas em si” e não aproveitam o potencial de unificação. Mas isolar conceitos e protocolos comuns para modelos de linguagem baseados em identificadores poderia levar à criação de componentes reutilizáveis para trabalhar com eles, semelhante ao que aconteceu no caso do EMF.
Não é que o Eclipse não tenha entendido essas questões. Em 2005
Em certo sentido, o projeto Handly foi projetado para resolver aproximadamente os mesmos problemas do EMF, mas para modelos baseados em handles, e principalmente modelos de linguagem (ou seja, representando elementos da estrutura de alguma linguagem de programação). Os principais objetivos definidos ao projetar o Handly estão listados abaixo:
- Identificação das principais abstrações da área temática.
- Reduzindo esforços e melhorando a qualidade da implementação de modelos de linguagem baseados em identificadores por meio da reutilização de código.
- Fornece uma API de meta-nível unificada para os modelos resultantes, possibilitando a criação de componentes IDE comuns que funcionam com modelos baseados em identificador de linguagem.
- Flexibilidade e escalabilidade.
- Integração com Xtext (em camada separada).
Para destacar conceitos e protocolos comuns, foram analisadas implementações existentes de modelos baseados em identificadores de linguagem. As principais interfaces e implementações básicas fornecidas pelo Handly são mostradas na Fig. 8.
Arroz. 8. Interfaces comuns e implementações básicas de elementos Handly
A interface IElement representa o identificador de um elemento e é comum aos elementos de todos os modelos baseados em Handly. A classe abstrata Element implementa o mecanismo generalizado de identificador/corpo (Fig. 9).
Arroz. 9. IElement e implementação genérica de identificador/corpo
Além disso, Handly fornece um mecanismo generalizado para notificar sobre alterações nos elementos do modelo (Fig. 10). Como você pode ver, ele é amplamente semelhante aos mecanismos de notificação implementados no modelo de recursos e no modelo Java e usa IElementDelta para fornecer uma representação unificada de informações de alteração de elemento.
Arroz. 10. Interfaces gerais e implementações básicas do mecanismo de notificação Handly
A parte Handly discutida acima (Fig. 9 e 10) pode ser usada para representar quase todos os modelos baseados em alças. Para criar linguística modelos, o projeto oferece funcionalidades adicionais - em particular, interfaces comuns e implementações básicas para elementos da estrutura do texto fonte, os chamados elementos de origem (Fig. 8). A interface ISourceFile representa um arquivo de origem e ISourceConstruct representa um elemento dentro do arquivo de origem. As classes abstratas SourceFile e SourceConstruct implementam mecanismos generalizados para suportar o trabalho com arquivos de origem e seus elementos, por exemplo, trabalhar com buffers de texto, vincular às coordenadas de um elemento no texto de origem, reconciliar modelos com o conteúdo atual de um buffer de cópia de trabalho , etc. A implementação desses mecanismos geralmente é um grande desafio, e o Handly pode reduzir significativamente o esforço de desenvolvimento de modelos de linguagem baseados em identificadores, fornecendo implementações básicas de alta qualidade.
Além dos mecanismos principais listados acima, o Handly fornece uma infraestrutura para buffers de texto e instantâneos, suporte para integração com editores de código-fonte (incluindo integração pronta para uso com o editor Xtext), bem como alguns componentes de UI comuns que trabalhar com editores de código-fonte. Modelos manuais, como estrutura de estrutura de tópicos. Para ilustrar suas capacidades, o projeto fornece vários exemplos, incluindo uma implementação do modelo Java em Handly. (Comparado com a implementação completa do modelo Java em JDT, este modelo é intencionalmente simplificado para maior clareza.)
Conforme observado anteriormente, o foco principal durante o design inicial e o desenvolvimento subsequente do Handly foi e continua sendo a escalabilidade e a flexibilidade.
Em princípio, os modelos baseados em alças são muito bem dimensionados “por design”. Por exemplo, o idioma handle/body permite limitar a quantidade de memória consumida por um modelo. Mas também existem nuances. Assim, ao testar a escalabilidade do Handly, foi descoberto um problema na implementação do mecanismo de notificação - quando um grande número de elementos era alterado, a construção de deltas demorava muito. Descobriu-se que o mesmo problema estava presente no modelo Java JDT, do qual o código correspondente foi adaptado. Corrigimos o bug no Handly e preparamos um patch semelhante para JDT, que foi recebido com gratidão. Este é apenas um exemplo onde a introdução do Handly em implementações de modelos existentes poderia ser potencialmente útil, porque neste caso tal bug poderia ser corrigido em apenas um lugar.
Para tornar tecnicamente viável a implementação do Handly em implementações de modelos existentes, a biblioteca deve ter flexibilidade significativa. O principal problema é manter a compatibilidade com versões anteriores em todo o modelo de API. Este problema foi resolvido em
A flexibilidade também tem outros aspectos. Por exemplo, Handly quase não impõe restrições à estrutura do modelo e pode ser usado para modelar linguagens de uso geral e de domínio específico. Ao construir a estrutura do arquivo fonte, Handly não prescreve nenhuma forma particular de representação AST e, em princípio, nem mesmo exige a presença de um AST propriamente dito, garantindo assim compatibilidade com quase todos os mecanismos de análise. Finalmente, Handly suporta integração total com o espaço de trabalho Eclipse, mas também pode trabalhar diretamente com sistemas de arquivos graças à sua integração com
Versão Atual
Conforme observado acima, um desses produtos é 1C:Enterprise Development Tools, onde Handly é usado desde o início para modelar elementos da estrutura de alto nível de linguagens 1C:Enterprise como a linguagem de programação integrada e a linguagem de consulta . Outro produto é menos conhecido do público em geral. Esse
Esperamos que após o lançamento da versão 1.0 com garantia de estabilidade da API e a saída do projeto do estado de incubação, o Handly tenha novos adotantes. Enquanto isso, o projeto continua testando e melhorando ainda mais a API, lançando dois lançamentos "principais" por ano - em junho (a mesma data do lançamento simultâneo do Eclipse) e em dezembro, fornecendo um cronograma previsível no qual os adotantes podem confiar. Também podemos acrescentar que a “taxa de bugs” do projeto permanece em um nível consistentemente baixo e o Handly tem trabalhado de forma confiável nos produtos dos primeiros usuários desde as primeiras versões. Para explorar ainda mais o Eclipse Handly, você pode usar
Fonte: habr.com