Recursos e o sistema de arquivos local

Quando o núcleo da plataforma está sendo executado e o plug-in de recursos está ativo, a área de trabalho é representada por uma ocorrência de IWorkspace, que fornece protocolo de acesso aos recursos que contém. Uma ocorrência de IWorkspace representa uma coleção de arquivos e diretórios associados no sistema de arquivos local. Você pode acessar a área de trabalho na classe do plug-in de recursos, emorg.eclipse.core.resources.

ResourcesPlugin.getWorkspace();

Quando o plug-in de recursos não está sendo executado, a área de trabalho existe somente no sistema de arquivos local e é visualizada ou manipulada pelo usuário através de ferramentas padrão com base no arquivo. Vamos ver a aparência da área de trabalho no disco, conforme explicamos a API do plug-in de recursos.

Nosso exemplo de árvore no disco

Quando você instalou a plataforma SDK, descompactou os arquivos em um diretório de sua escolha.  Chamaremos esse diretório de diretório raiz da plataforma. Ele é o diretório que contém o diretório plug-ins, entre outros. Dentro do diretório raiz da plataforma, há o diretório workspace, o qual é utilizado para armazenar os recursos criados e manipulados pela plataforma.  Se você olhar o diretório workspace, verá subdiretórios separados para cada projeto existente na área de trabalho. Nesses subdiretórios estão as pastas e os arquivos de cada projeto.

Se a SDK do nosso exemplo estiver instalada em c:\MySDK, no diretório c:\MySDK\workspace encontraremos subdiretórios nomeados após os projetos da área de trabalho, MyWeb e MyServlet. Eles são chamados de diretórios de conteúdo dos projetos. Os diretórios de conteúdo são criados pela plataforma quando o usuário cria um projeto.

Dentro de cada diretório, encontramos arquivos e pastas do projeto, cujo layout é exatamente o mesmo daquele na árvore de recursos da área de trabalho. Todos os nomes de arquivo são os mesmos e os conteúdos são os mesmos, quer sejam acessados através do sistema de arquivos ou da área de trabalho. Sem surpresas.

C:\MySDK\workspace  (raiz da área de trabalho)
    .metadata\ (diretório de meta-dados da plataforma)
    MyWeb\ (diretório de conteúdo do projeto para MyWeb)
        index.html
        images\
            logo.gif
    MyServlet\ (diretório de conteúdo do projeto para MyServlet)
        src\
            main.java
        bin\
            main.class
            main$$1.class

A plataforma tem um diretório especial .metadata para armazenamento de informações internas da plataforma. O diretório .metadata de uma área de trabalho é considerado uma "caixa preta".Informações importantes sobre a estrutura da área de trabalho, como referências de um projeto ou as propriedades de um recurso, são armazenadas na parte de meta-dados da área de trabalho e devem ser acessadas somente pelas ferramentas, através da API da plataforma.  Esses arquivos nunca devem ser editados ou manipulados utilizando a API genérica do sistema de arquivos.

Com exceção do diretório .metadata, as pastas e os arquivos no diretório da área de trabalho são insignificantes para as outras ferramentas.  Os arquivos e as pastas podem ser manipulados por ferramentas não integradas, como editores de texto e utilitários do sistema de arquivos.  O único problema é que o usuário deve ser cuidadoso ao editar esses arquivos na área de trabalho e externamente.  (Isso não é diferente de quando um usuário edita um arquivo utilizando duas ferramentas autônomas independentes).  A área de trabalho fornece operações de atualização para reconciliar a exibição dos recursos da área de trabalho com o estado real no sistema de arquivos.

Nosso exemplo de árvore no código

A API do recurso permite-nos manipular essa árvore de recursos no código. Aqui veremos alguns snippets de código, para experimentar rapidamente a API do recurso. A API do recurso é definida em um série de interfaces no org.eclipse.core.resources. Há interfaces para todos os tipos de recursos, como IProject, IFolder e IFile. O protocolo comum extensível é definido em IResource. Utilizamos também a interface de org.eclipse.core.runtime IPath, a qual representa caminhos segmentados, como caminhos do recurso ou do sistema de arquivos.

A manipulação de recursos é bastante similar à manipulação de arquivos utilizando java.io.File.  A API tem identificadores como base.  Quando você utiliza uma API como getProject ou getFolder, recebe como retorno um identificador para o recurso.    Não há garantia ou necessidade de que o recurso exista até você tentar fazer alguma coisa com o identificador.  Se você espera a existência de um recurso, pode utilizar o protocolo exists() para garantir isso.  

Para navegar pela área de trabalho a partir de um plug-in, devemos primeiro obter o IWorkspaceRoot, que representa o topo da hierarquia de recursos na área de trabalho.

IWorkspaceRoot myWorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot();

Depois de obtermos a raiz da área de trabalho, podemos acessar os projetos que estão nela.

IProject myWebProject = myWorkspaceRoot.getProject("MyWeb");
// abra se necessário
if (myWebProject.exists() && !myWebProject.isOpen())
    myWebProject.open(null);

Para poder manipular um projeto, precisamos primeiro abri-lo. A abertura do projeto lê a estrutura dele no disco e cria a representação da árvore de recursos do projeto do objeto na memória. A abertura de um projeto é uma operação explícita, pois cada projeto aberto consome memória para representar a árvore de recursos internamente e os projetos abertos participam de vários eventos do ciclo de vida do recurso (como construção), os quais podem ser demorados.  Em geral, os projetos fechados não podem ser acessados e aparecerão vazios, embora os recursos ainda estejam presentes no sistema de arquivos.

Você notará que muitos desses exemplos de recurso passam um parâmetro nulo durante a manipulação de recursos. Muitas operações do recurso são potencialmente pesadas o suficiente para garantir relatório de progresso e cancelamento do usuário. Se o código possui uma interface do usuário, geralmente você passará um IProgressMonitor, o qual permite que o plug-in de recursos relate o progresso conforme o recurso é manipulado e permite ao usuário cancelar a operação, se desejado.  Por enquanto, vamos simplesmente passar null, indicando nenhuma monitoração de progresso.

Após abrirmos um projeto, podemos acessar suas pastas e seus arquivos e também criar algumas adicionais.  No exemplo a seguir, criamos um recurso de arquivo a partir do conteúdo de um arquivo externo, localizado fora de nossa área de trabalho.

IFolder imagesFolder = myWebProject.getFolder("images");
if (imagesFolder.exists()) {
    // crie um novo arquivo
    IFile newLogo = imagesFolder.getFile("newLogo.gif");
    FileInputStream fileStream = new FileInputStream(
        "c:/MyOtherData/newLogo.gif");
    newLogo.create(fileStream, false, null);
    fileStream.close();
}

No exemplo acima, a primeira linha obtém um identificador para a pasta de imagens.  Devemos antes verificar se a pasta existe, para podermos fazer qualquer coisa interessante com ela.  Da mesma forma, quando obtemos o arquivo newLogo, o identificador não representará um arquivo real enquanto não criarmos o arquivo na última linha.  Neste exemplo, criamos o arquivo preenchendo-o com o conteúdo de logo.gif.

O próximo snippet é similar ao anterior, a exceção é que ele copia o arquivo newLogo do logotipo original, em vez de criar um novo a partir de seu conteúdo.

IFile logo = imagesFolder.getFile("logo.gif");
if (logo.exists()) {
    IPath newLogoPath = new Path("newLogo.gif");
    logo.copy(newLogoPath, false, null);
    IFile newLogo = imagesFolder.getFile("newLogo.gif");
...
}

Finalmente, criaremos outra pasta de imagens e moveremos o arquivo recentemente criado para ela. Renomeamos o arquivo como um efeito colateral dessa movimentação.

...
IFolder newImagesFolder = myWebProject.getFolder("newimages");
newImagesFolder.create(false, true, null);
IPath renamedPath = newImagesFolder.getFullPath().append("renamedLogo.gif");
newLogo.move(renamedPath, false, null);
IFile renamedLogo = newImagesFolder.getFile("renamedLogo.gif");

 

Muitos dos métodos de API do recurso incluem um flag booleano force, o qual especifica se os recursos que estão fora de sincronização com os arquivos correspondentes no sistema de arquivos local serão atualizados ou não.  Consulte IResource para obter mais informações.

Mapeando recursos para localizações no disco

No exemplo de árvore de recursos, assumimos que todos os diretórios de conteúdo do projeto estão no diretório workspace, abaixo do diretório raiz da plataforma (C:\MySDK\workspace). Essa é a configuração padrão para projetos.  No entanto, o diretório de conteúdo de um projeto pode ser remapeado para qualquer diretório arbitrário no sistema de arquivos, talvez uma unidade de disco diferente.

A capacidade de mapear a localização de um projeto independentemente dos outros permite ao usuário armazenar o conteúdo de um projeto no lugar apropriado para ele e sua equipe. O diretório de conteúdo de um projeto deve ser considerado "aberto a todos". Isso significa que os usuários podem criar, modificar e excluir recursos utilizando a área de trabalho e os plug-ins ou utilizando diretamente as ferramentas e os editores com base no sistema de arquivos.

Os nomes de caminho do recurso não são caminhos completos do sistema de arquivos. Os caminhos do recurso têm sempre como base a localização do projeto (normalmente o diretório workspace).  Para obter o caminho completo do sistema de arquivos até um recurso, você deve consultar sua localização utilizando IResource.getLocation().

É possível determinar a localização do sistema de arquivos de um recurso específico consultando sua localização, utilizando getLocation().  No entanto, não é possível utilizar IProjectDescription.setLocation para alterar sua localização, pois esse método é apenas um simples definidor de uma estrutura de dados.  

A API do recurso e o sistema de arquivos

Quando utilizamos a API dos recursos para modificar a árvore de recursos da nossa área de trabalho, os arquivos são alterados no sistema de arquivos além da atualização dos objetos do nosso recurso. E as alterações dos arquivos do recurso que acontecem fora da API da plataforma?

As alterações externas não serão refletidas nos objetos da área de trabalho e do recurso enquanto não forem detectadas pelo plug-in de recursos. Os clientes podem utilizar a API do recurso para reconciliar objetos da área de trabalho e do recurso com o sistema de arquivos local, silenciosamente e sem a intervenção do usuário.  O usuário sempre pode forçar explicitamente uma atualização  na exibição do navegador de recurso da área de trabalho.

Nota:  muitos dos métodos nas APIs de recurso incluem um parâmetro force, o qual especifica como os recursos que estão fora de sincronização com o sistema de arquivos devem ser tratados. A Referência da API para cada método fornece informações específicas sobre esse parâmetro. Outros métodos na API permitem o controle programático da atualização do sistema de arquivos, como IResource.refreshLocal(int depth, IProgressMonitor monitor). ConsulteIResource para obter informações sobre a utilização correta e os custos.