Desenvolvendo um plug-in para o Eclipse

O programa “Hello World” tradicional não faz muita coisa, mas pode ser de valor incalculável quando exploramos um novo ambiente de desenvolvimento. Nesse artigo, desenvolveremos um plug-in para o Eclipse e mostraremos como integra-lo ao Eclipse. Depois que você tiver lido esse artigo,você deve saber como usar o Eclipse para criar, executar e depurar um plug-in simples que estenda a plataforma do Eclipse. Você verá como configurar um projeto para seu plug-in, editar o código Java, compilar e executar ou depurar seu plug-in em outra cópia do Eclipse. Estaremos olhando os arquivos de manifesto do plug-in, extensões e pontos de extensão de forma a ver como os plug-ins são descritos no Eclipse e como são integrados na plataforma.

O Ambiente de Desenvolvimento de Plug-In (PDE, na sigla em inglês) do Eclipse fornece um ambiente confortável para a criação de plug-ins e a integração deles a plataforma Eclipse e/ou com outros plug-ins. Não iremos propor uma alternativa ao PDE aqui. O PDe é definitivamente o jeito certo a ser usado. Mas algumas vezes é útil fazer algumas coisas a mão de forma a ter um entendimento mais geral de como algo funciona e como as peças trabalham juntas. Essa é a abordagem que iremos usar nesse artigo. Desenvolveremos um plug-in simples implementando a versão Eclipse do exemplo “Hello World”. Isso permitirá que nos focemos nos relacionamentos entre os vários componentes do Eclipse e de nosso plug-in sem se incomodar com os detalhes do exemplo em si. Iremos ir o mais fundo que possível de modo que possamos ver o que está acontecendo de fato sob o capô. Com isso, esperamos que isso lhe dê um entendimento melhor do Eclipse, e lhe ajude a fazer um melhor uso do PDE, lhe dando algumas idéias de onde olhar quando algo não sair de acordo com o planejado.

O problema

Para o programa “Hello World”, vamos começar com um design simples. Iremos adicionar um botão a barra de ferramentas Workbench que quando for pressionado, exibe uma caixa de diálogo de informações contendo a string “Hello World”. Pressionando OK, essa caixa de diálogo será fechada. Nada sofisticado, e certamente nada que vá explorar toda a capacidade de extensão do Eclipse. Mas algo que podemos facilmente fazer por conta própria. E acontece que exemplos mais complicados seguem o mesmo padrão de forma que podemos obter muita informação desse exemplo simples.

Assim, vamos começar! Assumiremos que você já baixou a última versão do Eclipse, instalou ela e sabe como inicia-lo. Caso contrário, vá na página do Eclipse e siga as instruções do site.

Passo 1: Se preparando para escrever o código Java

Antes de começarmos, precisamos verificar algumas preferências para confirmar que está configurado de forma adequada para o desenvolvimento de plug-ins. Iremos configurar outras propriedades mais tarde nesse artigo, mas por agora, vamos apenas ajustas o layout padrão do projeto e selecionar a JRE que iremos usar.

Ajustando o layout padrão do projeto:  Edite as preferências do Java selecionando o item de menu Window->Preferences.  Expanda o item Java.  Clique em New Project item  e marque a opção Folders  radio. Verifique que “Source folder name” esteja configurada para ‘src’ e que “Output folder name” esteja ajustado para ‘bin’. Se você não alterar esses dados, todo os arquivos de classes e de código fonte serão salvos em diretórios na raiz do projeto. Isso pode ser bom para projetos pequenos, mas não é a estrutura desejada quando se estar criando programas maiores.

Nota: O plug-in “Hello World” assume que o layout do projeto foi alterado para usar as pastas ‘src’ e ‘bin’. Se você não fizer isso, obterá erros quando for testar o seu plug-in.

Passo 2: Criando um projeto de Plug-in

Agora estamos prontos para criar um projeto Java para o seu plug-in. Vá para a visão Navigator (Resource Perspective), e selecione File->New->Project. O assistente de criação do projeto tem uma lista de categorias cada uma com uma lista de projetos. Selecione a categoria Java  na lista a esquerda e Java project  na direita. A criação de um projeto Java versus outros projetos cria um projeto que entende os recursos do Java e como gerenciar mudanças neles. No assistente de projeto, informe um nome para seu plug-in. Geralmente é uma boa idéia usar o nome do plug-in como nome do projeto para tornar mais fácil carregar seu plug-in, e garantir que o nome não colida ou seja confundido com outro plug-in. Em nosso exemplo, usaremos o id do plug-in como nome do projeto. Informe org.eclipse.examples.helloworld.

Passo 3: Integrando com o Eclipse

Antes de podermos começar a escrever o código, precisamos determinar como iremos fazer a integração com o Eclipse. Isso se deve porque todas as extensões ao Eclipse são feitas através de plug-ins, e plug-ins integram-se uns aos outros através de extensões e pontos de extensão. Os plug-ins do Eclipse tipicamente fornecem extensões a plataforma que suportam algum recurso ou semântica adicional. O que precisamos é uma forma para que os plug-ins permitam que outros plug-ins mudem seu comportamento de forma controlada.

O Eclipse fornece um mecanismo de extensibilidade que é escalável, evita colisão de nomes, não precisa de compilação de todo o produto como uma unidade, e suporta múltiplas versões do mesmo componente ao mesmo tempo. O Eclipse faz isso pela introdução da noção de um plug-in que encapsula extensões funcionais para a Plataforma. Cada plug-in possui um nome, id, nome do fornecedor, versão, uma lista de plug-ins requeridos, e uma especificação para ser executado. Um plug-in pode também possui qualquer quantidade de pontos de extensão que fornecem um portal para que outros plug-ins possam adicionar funcionalidades. Essa é a forma com que o Eclipse permite que outros plug-ins manipulem a variabilidade suportada pelo seu plug-in. De forma a permitir a integração com outros plug-ins, um plug-in fornece extensões nesses pontos de extensões (talvez mesmo seus próprios pontos de extensão de forma a fornecer algum comportamento padrão).

Um plug-in é descrito em um arquivo XML chamado de arquivo de manifesto do plug-in. Esse arquivo é sempre chamado plugin.xml, e está localizado sempre no sub-diretório do plug-in. O Eclipse lê esses arquivos de manifesto e usam a informação para preencher e/ou atualizar um registro de informação que é usado para configurar a plataforma inteira.

Em nosso caso, queremos usar um botão na barra de ferramentas Workbench, assim o ponto de extensão que usaremos é o org.eclipse.ui.actionSets. Um action set é uma estratégia para adicionar e remover itens em um menu ou barra de ferramentas. Essa estratégia é executada se o usuário adicionar explicitamente a ação ao workbench. Um usuário pode adicionar um action set ao workbench invocando Window->Customize Perspective->Other...  para exibir as ações disponíveis. Para ativar uma das opções, você deve navegar pelas categorias, selecionar a ação desejada, e pressionar OK. Uma perspectiva pode adicionar uma ação ao layout da página inicial também, pela chamada a IPageLayout.addActionSet(id). Para detalhes sobre o ponto de extensão actionSet, abra a o material de ajuda localizado em Help->Help Contents...  e selecione Platform Plug-in Developer Guide->Reference->Extension Points Reference->Workbench. Selecione esse link e você será apresentado aos Pontos de Extensão da Plataforma.

Passo 4: Criando o Arquivo de Manifesto do plug-in

Agora que sabemos o que iremos fazer, vamos dizer a Eclipse sobre nosso plug-in pela criação do arquivo de manifesto. Use File->New->Other...  e selecione Simple->File  para criar um arquivo chamado plugin.xml no projeto org.eclipse.examples.helloworld.

Edite o arquivo plugin.xml para que ele pareça com isso:

<?xml version="1.0"?>
<plugin
	name="Eclipse Hello World Example"
	id="org.eclipse.examples.helloworld"
	version="0.0.0"
	provider-name="OTI">

    <requires>
	<import plugin="org.eclipse.core.resources"/>
        <import plugin="org.eclipse.ui"/>
    </requires>

    <runtime>
	<library name="helloworld.jar"/>
    </runtime>

    <extension point = "org.eclipse.ui.actionSets">
        <actionSet
            id="org.eclipse.examples.helloworld.HelloWorldActionSet"
            label="Hello World"
	    visible="true"
	    description="The action set for the Eclipse Hello World example">
	    <menu
		id="org.eclipse.examples.helloworld.HelloWorldMenu"
		label="Samples">
		<separator name="samples"/>
	    </menu>
	    <action id="org.eclipse.examples.helloworld.actions.HelloWorldAction"
		menubarPath="org.eclipse.examples.helloworld.HelloWorldMenu/samples"
		toolbarPath="Normal"
		label="Hello World"
		tooltip="Press to see a message"
		icon="icons/helloworld.gif"
		class="org.eclipse.examples.helloworld.HelloWorldAction"/>
        </actionSet>
    </extension>
</plugin>

Você pode usar o Eclipse para editar esse arquivo usando o editor de texto padrão. Para fazer isso, selecione Window->Preferences, expanda a entrada Workbench, e selecione File Associations. Adicione a extensão xml, e adicione “Text Editor” a suas associações. Agora quando você tentar abrir no editor um arquivo xml,  você abrirá o editor de texto padrão. Isso funcionará muito bem para o nosso exemplo simples. O PDE facilita muito a criação de plug-ins mais complexos.

Agora vamos dar uma olhada no arquivo de manifesto e ver exatamente o que ele possui. Em primeiro lugar, vemos que declaramos um plugin. Esse é sempre o elementos raiz do arquivo de manifesto. Os atributos desse elemento fornecem o nome do plug-in, seu id, versão e nome do fornecedor. O id é o atributo realmente interessante. Ele especifica o identificador que a plataforma usa para referenciar esse plug-in. Como esse nome precisa ser único para todos os plug-ins instalados, usaremos as convenções para nome de pacotes em Java para criar um nome único. Qualquer coisa funcionará, mas essa é uma convenção razoável que deve ser seguida. Você verá como esses ids são usados um pouco mais adiante quando tivermos que usar o ponto de extensão de outro plug-in.

O elemento requires  e onde se especifica todos os outros plug-ins dos quais seu plug-in depende. Em nosso caso, estamos usando a extensão actionSets dp plugin org.eclipse.ui , assim especificamos esse plug-in aqui.

O elemento runtime  é a forma como dizemos qual plataforma usaremos para encontrar as classes de nosso plug-in. Essencialmente, os elementos ‘requires’ e ‘runtime’ juntos especificam o ‘classpath’ do plug-in. Essa abordagem permite que cada plug-in tenha seu próprio ‘classpath’ independente uns dos outros. Além disso, cada plugin possui seu próprio ‘classloader’ que é usado para carregar todas as classes definidas por esse plug-in (isto é, as classes encontrada nas declarações de bibliotecas).

Agora finalmente temos integração de verdade. O elementos ‘extension’ (em nosso arquivo plugin.xml) descreve uma extensão ao ponto de extensão de org.eclipse.ui.actionSets. Em nosso exemplo, estamos estendendo o ponto de extensão actionSets do plug-in org.eclipse.ui. O id de nossa extensão, como a plataforma se refere a ela, é org.eclipse.examples.helloworld.HelloWorldActionSet, enquanto o nome de exibição é “Hello World”. Se você olhar a documentação referenciada acima para os pontos de extensão, verá que podem ter vários elementos de ação que descrevem as ações do conjunto. Cada ação possui um atributo de classe que especifica a classe que implementa a interface necessária, org.eclipse.ui.IWorkbenchWindowActionDelegate. Essa é a forma como temos que implementar a nossa extensão. Você precisará também fornecer um arquivo helloworld.gif para fornecer um ícone para nossa ação. Crie a pasta de ícones em sua pasta de plug-ins. Todos os arquivos do plug-in e caminhos de pastas são relativos a pasta do plug-in.

Não fique confuso entre um elemento de ponto de extensão e um elemento de extensão com um atributo de ponto. O primeiro define um gancho  para a plataforma enquanto o segundo especifica e instância o uso dessa gancho. O segundo é o id do ponto de extensão que você está estendendo.

Passo 5: Ajustando o projeto do plug-in

Mude para a perspectiva Java se ainda não estiver nela com Window->Open Perspective->Other  e selecione a perspectiva Java (ou se a opção Java estiver disponível no menu, pode seleciona-la diretamente). Depois selecione a aba ‘packages explorer’ para ver os pacotes do seu projeto. Você deve ver apenas os pacotes especificados em seu ‘build path’ do Java até agora, provavelmente apenas a entrada JRE_LIB de seu rt.jar. Já que iremos estar usando a interface IWorkbenchWindowActionDelegate , e outras partes da plataforma para desenvolver nosso exemplo, precisaremos incluir os plug-ins referenciados em nosso ‘build path’.

A partir do arquivo de manifesto do plug-in, podemos ver que precisamos do plug-in org.eclipse.ui. A referencia ao plug-in no elemento ‘requires’ de nosso plug-in permite que a plataforma encontre as classes que nós fazemos referência durante a execução, mas não ajuda o compilador durante o desenvolvimento. Precisamos obter essa execução do plug-in no ‘build path’ de nosso projeto para que possamos compila-lo. Para fazer isso, selecione o projeto e visualize suas propriedades; dê um clique com o botão direito no projeto. Selecione a entrada Java Build Path  e clique na aba Libraries . Depois clique no botão Add External JARs...  e navegue até <your eclipse install directory>/eclipse/plugins/org.eclipse.ui_2.0.0, o diretório onde está a versão 2.0 do plug-n Eclipse UI.

Veja aqui porque gostamos de ter os ids do plug-in em correspondência com os nomes dos diretórios? Torna bem mais fácil encontrar as coisas assim. No diretório org.eclipse.ui_2.0.0 você verá o arquivo workbench.jar. Selecione esse arquivo para adiciona-lo ao nosso ‘build path’. O plug-in Eclipse UI depende do plug-in Eclipse SWT, assim precisamos adicionar ele também: org.eclipse.swt.win32_2.0.0->ws->win32  contém swt.jar, assumindo que você esteja no Windows. Existem diretórios similares para usuários Linux que estejam usando Motif ou Gtk. A plataforma automaticamente fornece um plug-in especial de suporte a execução: org.eclipse.core.runtime_2.0.0  – você também deve adicionar o arquivo runtime.jar desse diretório ao seu ‘build path’. Se o seu plug-in depende de algum outro plug-in, você precisará adicionar seus arquivos jar também.

Nota: O Eclipse 2.1 re-arranjou os plug-ins relacionados a UI. O workbench.jar passou a estar localizado no diretório org.eclipse.ui.workbench_2.1.0. Além disso, o plug-in JFace é necessário. O arquivo jface.jar pode ser encontrado em org.eclipse.jface_2.1.0. Os demais plug-ins podem ser encontrados em seus respectivos diretórios.

Agora estamos prontos para escrever o código e compilar o plug-in com os arquivos workbench.jar e swt.jar. O workbench possui o conjunto do JDK, o projeto possui  todos os arquivos jar necessários, e o arquivo de manifesto diz quais classes teremos que iniciar.

Passo 6: Implementando a interface IWorkbenchWindowActionDelegate

Nesse exemplo, nossa implementação da interface IWorkbenchWindowActionDelegate  é org.eclipse.examples.helloworld.HelloWorldAction. Vá dar uma olhada no JavaDoc sobre essa interface para ver os métodos que precisamos implementar. O JavaDoc está disponível a partir do menu Help->Help Contents. Selecione Platform Plug-in Developer Guide  e expanda o item de menu Reference->API Reference->Workbench->org.eclipse.ui. Além do uso de convenções de nomenclatura padrões do Java, você deve considerar a inclusão do id do plug-in como parte de seu nome de pacote. Mesmo isso não sendo obrigatório, ajudará você a manter o código organizado.

Para criar a classe de implementação, primeiro criaremos um pacote para nosso plug-in. Selecione a pasta src do projeto org.eclipse.examples.helloworld  na visão ‘packages’, dê um clique com o botão direito e selecione New->Package. Crie um pacote chamado org.eclipse.examples.helloworld.

Em seguida, selecione o pacote recentemente criado, dê um clique com o botão direito, e selecione New->Class. Se você preferir a barra de ferramenta, existem botões para criar um pacote e uma classe, entre outros botões específicos do Java. Na caixa de diálogo que aparece, verifique se o nome do pacote é o que acabamos de criar (se não for, você deve seleciona-lo primeiro), e preencha o nome da classe como HelloWorldAction como especificado no atributo ‘class’ do elemento de ação em nossa extensão (veja o arquivo de manifesto plugin.xml). A super classe java.lang.Object funciona bem, mas adicione a interface IWorkbenchWindowActionDelegate. Você verá a lista de seleção a medida que digita. Selecione o item correspondente a interface  desejada e clique em OK. Você verá org.eclipse.ui.IWorkbenchWindowActionDelegate  na lista de interfaces que sua classe irá implementar. Por conveniência, clique na caixa de verificação Inherited abstract methods  de forma que o assistente de criação de uma nova classe crie pontas para todas os métodos de interfaces que você precisa implementar. Isso salvará você de um bocado de digitação. Se você não ver a classe na lista de seleção, essa é uma boa indicação de que o seu ‘build path’ não inclui tudo o que é necessário. Verifique o seu ‘build path’ nas preferências do projeto e tente novamente.

Agora temos nossa classe de implementação de IWorkbenchWindowActionDelegate. Da interface temos quatro métodos a implementar, init  e dispose  de IWorkbenchWindowActionDelegate, e run  e selectionChanged  de IActionDelegate. Edite a classe, e forneça as implementação dadas abaixo:

package org.eclipse.examples.helloworld;

import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.swt.widgets.Shell;

/** HelloWorldAction is a simple example of using an
 * action set to extend the Eclipse Workbench with a menu
 * and toolbar action that prints the "Hello World" message.
 */
public class HelloWorldAction implements IWorkbenchWindowActionDelegate {
	IWorkbenchWindow activeWindow = null;

	/** Run the action. Display the Hello World message
	 */
	public void run(IAction proxyAction) {
		// proxyAction has UI information from manifest file (ignored)
		Shell shell = activeWindow.getShell();
		MessageDialog.openInformation(shell, "Hello World", "Hello World!");
	}

	// IActionDelegate method
	public void selectionChanged(IAction proxyAction, ISelection selection) {
		// do nothing, action is not dependent on the selection
	}

	// IWorkbenchWindowActionDelegate method
	public void init(IWorkbenchWindow window) {
		activeWindow = window;
	}

	// IWorkbenchWindowActionDelegate method
	public void dispose() {
		//  nothing to do
	}
}

O código não é muito complicado, de forma que não cobriremos ela em detalhes. Outros artigos podem ser encontrados na Internet falando dos recursos específicos do Eclipse que usamos, mas aqui manteremos o foco em plug-ins e a integração de ponta a ponta ao invés de especificidades do código desse artigo.

Passo 7: Testando o seu plug-in

Estamos prontos para testar nosso plug-in! A melhor forma para fazer isso é usar dois workbenchs do Eclipse, um para o desenvolvimento do Eclipse, e um segundo para teste e depuração. Vamos chama-los de workbench de desenvolvimento e de teste para evitar confusão.  Não usaremos a mesma instância do Eclipse para desenvolvimento e teste por várias razões:

  • Você tem que reiniciar o workbench toda vez que fizer uma alteração no plug-in para que ele seja recarregado adequadamente. Se você usar o ambiente de desenvolvimento para isso, terá que reinicia-lo toda vez.
  • Se houver um problema em seu plug-in, isso poderia suspender o workbench de desenvolvimento tornando difícil localizar e consertar o problema.
  • Você não pode depurar um workbench com o mesmo workbench que está executando o depurador. Isso se deve porque quando o depurador atinge um breakpoint, o workbench inteiro é interrompido.

Antes de iniciar um workbench de teste, você precisa informar ao Eclipse onde os plug-ins necessários estão localizados. Edite as preferências de Desenvolvimento de Plug-Ins selecionando o item de menu Window->Preferences. Expanda o item Plug-In Development. Selecione Target Platform e clique no botão Not in Workspace no lado direito. Você observará que os itens selecionados na lista a esquerda do botão estarão todos marcados. Finalmente clique no botão OK e aceite essas mudanças.

Para iniciar o Eclipse com o  Eclipse, simplesmente execute Run->Run As->Run-time Workbench. O Eclipse automaticamente iniciará sendo executado em um segundo workbench. Seja paciente pois essa operação pode levar bastante tempo; quando um segundo workbench é aberto a operação está completa. Para visualizar a localização desse segundo workbench exiba a configuração de carregamento via Run->Run....  Alternativamente, essas duas funções podem ser conseguidas através do ícone Run da barra de ferramentas do Workbench.

Agora podemos testar as ações do nosso ‘Hello World’. Você verá o ícone do ‘Hello World’ que foi especificado no atributo ícone do elemento ‘action’ no nosso arquivo de manifesto na barra de ferramentas Workbench (se não informou um ícone, será mostrado um quadrado cinza ou vermelho). Mova o cursor sobre ele e você verá o texto de ajuda informado. Clique e você verá a mensagem. Não é tão simplório quando printf("Hello World");  mas parece bem legal. Para desligar o ‘Hello World’ (e remover o botão associado), selecione Window->Customize Perspective...  expanda a categoria Other. Agora você pode desmarcar o item ‘Hello World’.

Depurando o seu plug-in

A depuração do plug-in é bem fácil. Apenas abra o código Java e coloque um breakpoint nos locais que quiser iniciar a depuração. Depois depure o seu workbench de teste selecionando Run->Debug As->Run-time Workbench . O workbench irá abrir uma página de perspectiva de depuração, e você verá o processo do Eclipse sendo executado. O Eclipse será aberto e estará pronto para que você invoque o plug-in. Novamente, ative o ‘Hello World’ e clique no botão. O workbench de teste parará em seu breakpoint e você verá o código, o breakpoint e as variáveis na perspectiva de depuração em seu workbench de desenvolvimento. Siga em frente e experimente o depurador. Depois pressione o botão ‘resume’ quando tiver finalizado. Lebre-se de que você pode ter apenas um workbench ativo, de forma que você precisará fechar seu workbench de teste entre aos teste.

Conclusão

E acabamos de ver o desenvolvimento completo de um plug-in para o Eclipse do design até a depuração e teste. Fizemos todo o desenvolvimento, teste e depuração usando o próprio Eclipse e a ferramenta de desenvolvimento Java. O exemplo não faz muito, e a complexidade por função é bem alta. Mas plug-ins mais complexos seguem o mesmo padrão, e o Eclipse fornece muito mais recursos do que o que vimos nesse exemplo simples. Você deve agora ter uma boa idéia de como todas as peças se encaixam e o que significa desenvolver e integrar um plug-in. Agora é hora de fazer alguma coisa real. Você irá querer suar o PDE para isso.

Traduzido de