Recursos e sistema de ficheiros

Quando a plataforma está em execução e o plug-in de recursos está activo, o espaço de trabalho é representado por uma instância de IWorkspace, a qual faculta protocolo para aceder aos recursos que contém. Uma instância IWorkspace representa uma recolha associada de ficheiros e directórios contidos num ou em mais sistemas de ficheiros. Pode aceder ao espaço de trabalho a partir da classe do plug-in de recursos (definida em org.eclipse.core.resources).

   IWorkspace workspace = ResourcesPlugin.getWorkspace();

Quando o plug-in de recursos não estiver a ser executado, o espaço de trabalho existe apenas no sistema de ficheiros e é visualizado ou manipulado pelo utilizador através das ferramentas padrão baseadas em ficheiros. Vejamos como é um espaço de trabalho em disco enquanto explicamos a API do plug-in de recursos.

A nossa árvore exemplo em disco

Ao iniciar o SDK da plataforma, foi-lhe pedido que facultasse um directório espaço de trabalho. Trata-se do directório em que vários plug-ins armazenam metadados interessantes que são exclusivos de uma determinada instância da plataforma. Por predefinição, o plug-in de recursos armazena cada projecto num subdirectório do directório do espaço de trabalho. Nestes subdirectórios estão as pastas e os ficheiros que cada projecto contém.

Suponha que selecciona o directório c:\MySDK\workspace para o espaço de trabalho. Dentro deste directório encontram-se subdirectórios denominados com os nomes dos projectos do espaço de trabalho, ou seja MyWeb e MyServlet. Estes chamam-se os directórios de conteúdo dos projectos. Os directórios de conteúdo são criados pela plataforma quando o utilizador cria um projecto.

Dentro de cada directório, encontramos os ficheiros e as pastas de um projecto, esquematizados exactamente da mesma forma que na árvore de recursos do espaço de trabalho. Todos os nomes de ficheiros são os mesmos e o conteúdo dos ficheiros é o mesmo, quer acedido do sistema de ficheiros quer do espaço de trabalho. A única surpresa é o ficheiro .project, que explicaremos a seguir.

   C:\MySDK\workspace  (workspace root)
      .metadata\ (platform metadata directory
      MyWeb\ (project content directory for MyWeb)
	 .project
         index.html
         images\
            logo.png
      MyServlet\ (project content directory for MyServlet)
	 .project
         src\
            main.java
         bin\
            main.class

A plataforma tem um directório .metadata especial para reter informações internas da plataforma. O directório .metadata de um espaço de trabalho é considerado uma "caixa negra". As informações importantes sobre a estrutura do espaço de trabalho como, por exemplo, referências de projecto ou propriedades de um recurso, são armazenadas na parte de metadados do espaço de trabalho e só devem ser acedidas por ferramentas através da API da plataforma.  Estes ficheiros nunca devem ser editados nem manipulados com a API genérica do sistema de ficheiros.

Além disso, cada projecto tem o seu próprio ficheiro .project, em que são mantidos metadados acerca do projecto. Este ficheiro é basicamente um equivalente em disco das informações detectadas na IProjectDescription de um projecto.  

À excepção Apart do directório .metadata e dos ficheiros .project, as pastas e os ficheiros do directório do espaço de trabalho estão à mercê de outras ferramentas. Os ficheiros e as pastas podem ser manipulados por ferramentas não integradas como, por exemplo, editores de texto e utilitários de sistema de ficheiros. A única questão é que o utilizador deve ter cuidado ao editar estes ficheiros tanto no espaço de trabalho como externamente. (Não é diferente de quando o utilizador edita um ficheiro com duas ferramentas autónomas independentes.) A área de trabalho faculta operações de renovação para reconciliar a vista de recursos do espaço de trabalho com o verdadeiro estado no sistema de ficheiros e renova periodicamente o espaço de trabalho com base no estado do sistema de ficheiros.

A nossa árvore exemplo em código

A API de recursos permite manipular esta árvore de recursos em código. Vamos ver algumas porções de código para breve amostragem da API de recursos. A API de recursos é definida numa série de interfaces em org.eclipse.core.resources. Há interfaces para todos os tipos de recursos como, por exemplo, IProject, IFolder e IFile. O protocolo comum extensivo está definido em IResource. Também utilizamos o IPath da interface org.eclipse.core.runtime, o qual representa caminhos segmentados como, por exemplo, caminhos de recursos ou sistemas de ficheiros.

A manipulação de recursos é muito semelhante à de ficheiros com java.io.File.  A API baseia-se em pegas. Quando se utiliza APIs como getProject ou getFolder, recebe-se uma pega para o recurso.  Não há garantias nem requisitos de que o próprio recurso exista até tentar efectuar algo com a pega. Se esperar que um recurso exista, poderá utilizar o método exists para garantir que é o caso.  

Para navegar no espaço de trabalho a partir de um plug-in, primeiro é necessário obter a IWorkspaceRoot que representa o topo da hierarquia do recurso no espaço de trabalho.

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

Assim que tivermos uma raiz de espaço de trabalho, podemos aceder aos projectos no mesmo.

   IProject myWebProject = myWorkspaceRoot.getProject("MyWeb");
   // open if necessary
   if (myWebProject.exists() && !myWebProject.isOpen())
      myWebProject.open(null);

Antes de podermos manipular um projecto, temos que o abrir. A abertura do projecto lê a estrutura do mesmo a partir do disco e cria a representação de objectos em memória da árvore de recursos do projecto. Abrir um projecto é uma operação explícita dado que cada projecto aberto consome memória para representar a árvore de recursos internamente e os projectos abertos podem participar em diversos eventos de ciclo de vida de recursos (como, por exemplo, construção), os quais se podem revelar morosos. Regra geral, não se pode aceder a projectos fechados e estes aprecem vazios mesmo que os recursos ainda estejam presentes no sistema de ficheiros.

Irá reparar que muitos destes exemplos de recursos transmitem um parâmetro null quando se manipulam recursos. Muitas das operações de recursos são potencialmente pesadas o bastante para dar lugar a indicação do progresso e cancelamento por parte do utilizador. Se o código tiver uma interface de utilizador, irá normalmente transmitir um IProgressMonitor, o qual permite que o plug-in de recursos indique o progresso à medida que o recurso for manipulado e permite ao utilizador cancelar a operação se o quiser. Por agora, transmitimos simplesmente null, a indicar que não há supervisor de progresso.

Assim que tivermos um projecto aberto, poderemos aceder às pastas e aos ficheiros e criar adicionais. No exemplo seguinte criamos um recurso de ficheiro a partir do conteúdo de um ficheiro que se encontra fora do espaço de trabalho.

   IFolder imagesFolder = myWebProject.getFolder("images");
   if (imagesFolder.exists()) {
      // create a new file
      IFile newLogo = imagesFolder.getFile("newLogo.png");
      FileInputStream fileStream = new FileInputStream(
         "c:/MyOtherData/newLogo.png");
      newLogo.create(fileStream, false, null);
      // create closes the file stream, so no worries.
   }

No exemplo supra, a primeira linha obtém uma pega para a pasta imagens. Temos de verificar se a pasta existe antes de poder fazer qualquer coisa. Do mesmo modo, quando obtemos o ficheiro novoLogo, a pega não representa um ficheiro real enquanto não criarmos o ficheiro na última linha. Neste exemplo, criamos o ficheiro preenchendo-o com o conteúdo de logo.png.

A porção de código seguinte é semelhante à anterior, salvo em que copia o ficheiro novoLogo do logo original ao invés de criar um novo a partir do conteúdo.

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

Por fim, criamos outra pasta imagens e movemos o ficheiro acabado de criar para dentro dela. Mudamos o nome ao ficheiro como efeito secundário de o mover.

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

A maioria dos métodos da API de recursos incluem um sinalizador booleano de força que especifica se os recursos dessincronizados com os ficheiros correspondentes no sistema de ficheiros serão actualizados. Consulte IResource para mais informações. Também pode utilizar IResource.isSynchronized para determinar se certo recurso está em sincronia com o sistema de ficheiros.

Correlacionar recursos com localizações em disco

Na árvore de recursos exemplo, partimos do princípio de que todos os directórios de conteúdo de projectos estavam no directório espaço de trabalho abaixo do directório raiz da plataforma (C:\MySDK\workspace). Trata-se da configuração predefinida para projectos. Contudo, o directório do conteúdo do projecto pode ser correlacionado com qualquer directório arbitrário num sistema de ficheiros de segurança, até mesmo numa máquina diferente.

A capacidade de correlacionar a localização de um projecto independente de outros projectos permite ao utilizador armazenar o conteúdo de um projecto num lugar que faça sentido para o projecto e para a equipa do projecto. O directório de conteúdo de um projecto deve ser considerado "aberto". Significa isto que os utilizadores podem criar, modificar e eliminar recursos, através da área de trabalho e de plug-ins ou usando directamente ferramentas e editores baseados no sistema de ficheiros.

Os nomes de caminhos de recursos não são caminhos de sistema de ficheiros completos. Os caminhos de recursos baseiam-se sempre na localização do projecto (geralmente o directório espaço de trabalho). Para obter a totalidade do caminho do sistema de ficheiros de um recurso, terá de consultar a respectiva localização através da utilização de IResource.getLocationURI.  Contudo, não é possível usar IProjectDescription.setLocation para alterar a localização porque esse método é um mero definidor de estruturas de dados.  

Em contrapartida, se pretender obter o objecto de recurso correspondente de um determinado caminho de sistema de ficheiros, pode utilizar IWorkspaceRoot.findFilesForLocationURI ou IWorkspaceRoot.findContainersForLocationURI.

API de recursos e o sistema de ficheiros

Quando se utiliza a API de recursos para modificar a árvore de recursos do espaço de trabalho, os ficheiros são alterados no sistema de ficheiros além de actualizar os nossos objectos de recursos. E as alterações aos ficheiros de recursos que se dão fora da API da plataforma?

As alterações externas aos recursos não se reflectem no espaço de trabalho e nos objectos de recursos até detectados pelo plug-in de recursos. O plug-in de recursos também usa um mecanismo apropriado para cada sistema operativo nativo particular para descobrir alterações externas feitas no sistema de ficheiros. Além disso, os clientes podem utilizar a API de recursos para reconciliar objectos de espaço de trabalho e de recursos com o sistema de ficheiros local calmamente e sem intervenção do utilizador. O utilizador também pode forçar explicitamente uma renovação na vista do navegador do recursos da área de trabalho.

Muitos dos métodos nas APIs de recursos incluem um parâmetro force que especifica como devem ser tratados os recursos que estejam fora de sincronia com o sistema de ficheiros. A Referência de API para cada método proporciona informações específicas sobre este parâmetro. Os métodos adicionais na API permitem controlo programático da renovação do sistema de ficheiros como, por exemplo, IResource.refreshLocal(int depth, IProgressMonitor monitor). Consulte IResource para mais informações sobre a devida utilização e os custos.

Os plug-ins que pretendam fornecer mecanismos próprios para renovar periodicamente o espaço de trabalho com base no estado do sistema de ficheiros externo poderão fazê-lo com o ponto de extensão org.eclipse.core.resources.refreshProviders. Consulte Fornecedores de renovação para mais informações.