Roteiro de Modelo para Integração de Modelo Lógico

Esta é uma lista do que os provedores de modelos podem fazer para aproveitar as vantagens do suporte de modelo lógico Equipe:

  1. Adapte os elementos de modelo em visualizações de modelo para ResourceMapping para permitir que as operações baseadas em recurso apareçam nos elementos de modelo.
  2. Registre um ModelProvider para assegurar-se de que o modelo seja consultado quando operações forem executadas nos recursos relacionados ao modelo.
  3. Utilize o ResourceChangeValidator ao executar operações em recursos para assegurar-se de que todos os possíveis efeitos colaterais sobre os elementos de modelo relacionados a esses recursos sejam revelados ao usuário.
  4. Implemente um IResourceMappingMerger para tomar parte nas mesclagens sem periféricos que envolvem os recursos relacionados ao modelo.
  5. Registre um teamContentProvider para tomar parte nos visualizadores de Equipe, como visualizações de mesclagem.
  6. Forneça um IHistoryPageSource para mostrar o histórico de modelo lógico na visualização de histórico de Equipe.
  7. Utilize a API do Sistema de Arquivo do Eclipse para acessar o estado remoto de projetos de modelo.
  8. Utilize a API SynchronizationStateTester para assegurar a decoração correta de elementos de modelo que não têm um mapeamento direto para os recursos.

As seções a seguir descrevem cada um desses pontos mais detalhadamente. O plug-in org.eclipse.team.examples.filesystem contém um exemplo que ilustra vários desses pontos. Você pode registrar a saída do projeto do repositório CVS e utilizá-lo como referência enquanto está lendo este tutorial. Renúncia: O código-fonte no plug-in de exemplo pode ser alterado com o tempo. Para obter uma cópia que corresponda à utilizada neste exemplo, você pode efetuar o registro de saída do projeto utilizando a marcação da versão 3.2 (muito provavelmente R3_2) ou uma marcação de data de 28 de junho de 2006.

Mapeamentos de Recursos

A API de Mapeamento de Recurso Básico

A API de mapeamento de recurso é planejadamente simples, com manipulações de modelo lógico omitidas. Um cliente não pode utilizar essa interface para exibir modelos lógicos ou adquirir conhecimento adicional interessante sobre ela. Sua proposta é simplesmente mapear um ou mais elementos de modelo para recursos de espaço de trabalho.

A API consiste nas seguintes classes:

Há dois tipos de plugins que deverão estar interessados em mapeamentos de recursos. Aqueles que fornecem um modelo que consiste, ou persiste, em recursos no espaço de trabalho e aqueles que desejam executar operações em recursos. O primeiro é coberto na próxima seção; o último, no Roteiro de Repositório para Integração de Modelo Lógico.

Adaptando um Modelo a um ResourceMapping

Plugins que adaptaram seus objetos modelo ao IResource a fim de obter ações de recurso específico mostradas no menu de contexto agora poderão adaptar-se ao ResourceMapping, se uma descrição mais precisa de como o objeto se adapta aos recursos for útil. Entretanto, eles não precisarão proceder dessa maneira se não houver utilidade. Por exemplo, uma unidade de compilação Java (isto é, arquivo *.java mostrado em uma visualização JDT) que atualmente se adapta ao IFile não precisa se adaptar ao ResourceMapping, visto que nada é ganho. Entretanto, um pacote Java deve adaptar-se ao ResourceMapping para indicar que o pacote consiste apenas nos arquivos da pasta correspondente e não das subpastas.

A maneira preferencial de adaptar elementos de modelo a um mapeamento de recurso é utilizar um depósito de informações do adaptador. Segue a marcação XML para contribuição de um depósito de informações do adaptador em um manifesto de plug-in.

   <extension
point="org.eclipse.core.runtime.adapters">
<factory
class="org.eclipse.example.library.logical.AdapterFactory"
adaptableType="org.eclipse.example.library.Book">
<adapter type="org.eclipse.core.resources.mapping.ResourceMapping"/>
</factory>
<factory
class="org.eclipse.example.library.logical.AdapterFactory"
adaptableType="org.eclipse.example.library.Library">
<adapter type="org.eclipse.core.resources.mapping.ResourceMapping"/>
</factory>
...
</extension>

A implementação do depósito de informações do adaptador seria algo semelhante a isto:

public class AdapterFactory implements IAdapterFactory {
public Object getAdapter(Object adaptableObject, Class adapterType) {
if((adaptableObject instanceof EObject) && adapterType == ResourceMapping.class) {
return new EObjectResourceMapping((EObject)adaptableObject);
}
return null;
}

public Class[] getAdapterList() {
return new Class[] {ResourceMapping.class};
}
}

Objetos modelo podem implementar a interface IAdaptable. Quando assim for feito, eles deverão garantir que o gerenciador de adaptador de Plataforma seja consultado. Isso pode ser feito subclassificando PlatformObject ou utilizando a seguinte linha de código:

Platform.getAdapterManager().getAdapter(Object, Class)

A abordagem mencionada anteriormente é a preferencial. Entretanto, o objeto modelo pode implementar a interface IAdaptable e fornecer uma implementação getAdapter(Class) que cria/retorna uma instância de ResourceMapping explicitamente quando uma é solicitada. Essa é uma abordagem mais direta, porém, menos desejável, visto que o modelo deverá ter conhecimento explícito da adaptação aos recursos.

Em alguns casos, o provedor de um modelo lógico pode não querer que seu modelo se adapte ao IResource em cada contexto ou querer que o objeto se adapte de forma diferente para contribuições de objeto e para outros contextos. A UI do ambiente de trabalho fornece uma API especial de adaptador intermediário, IContributorResourceAdapter, para essa finalidade. Quando os objetos estão sendo adaptados ao IResource no contexto de contribuições de objeto, o ambiente de trabalho primeiramente tenta adaptar o recurso ao IContributorResourceAdapter antes de tentar adaptar ao IResource diretamente. Foi incluída uma nova sub-interface dessa interface, IContributorResourceAdapter2, a qual fornece a mesma capacidade para ResourceMapping. A única diferença é que o provedor de modelo deve registrar um depósito de informações para o IContributorResourceAdapter, visto que o ambiente de trabalho faz uma verificação instanceof para ver se o adaptador contribuído também é uma instância de IContributorResourceAdapter2.

A implementação da subclasse ResourceMapping para um pacote Java seria algo semelhante a isto:

public class JavaPackageResourceMapping extends ResourceMapping {
IPackageFragment package;
...
public getModelObject() {
return package;
}
public ResourceTraversals[] getTraversals(
ResourceMappingContext context,
IProgressMonitor monitor) {
return new ResourceTraversal[] {
new ResourceTraversal(
new IResource[] { package.getCorrespondingResource() },
IResource.DEPTH_ONE, IResource.NONE)
}
}
}

Esse é um mapeamento razoavelmente direto, para que a implementação não seja complexa. A complexidade da implementação do mapeamento de recurso, certamente, variará conforme o modelo.

Contexto de Mapeamento de Recurso

Uma das vantagens de uma API de Mapeamento de Recurso é o fato de ela permitir que plug-ins implementem qualquer operação que desejarem, em termos de mapeamentos de recurso (por exemplo, atualização CVS, confirmação CVS, tag CVS, decoração pesada, etc.). Entretanto, a API apresentada até aqui trata apenas do estado local do modelo. Ao trabalhar com um modelo que pode ser compartilhado entre desenvolvedores, você termina em uma situação em que o estado remoto do modelo (isto é, o estado do modelo cuja entrada foi registrada no repositório por outro usuário) pode diferir do estado no espaço de trabalho. Se você executou uma atualização CVS, desejará que o estado local do modelo corresponda ao estado remoto, mesmo que isso signifique a necessidade de incluir arquivos adicionais ou remover alguns arquivos.

Isso não é problema para alguns modelos lógicos. Por exemplo, pacote java é um contêiner visitado a uma profundidade de um, independentemente do estado remoto do modelo. Isso determinado, um provedor de repositório pode facilmente determinar que as exclusões de saída deverão ser incluídas ao confirmar ou que adições de entrada deverão ser incluídas ao atualizar. Entretanto, os recursos que constituem alguns modelos lógicos podem ser alterados além do tempo. Por exemplo, os recursos que constituem um elemento de modelo podem depender do conteúdo de um arquivo de manifesto (ou outro mecanismo semelhante). Para que o mapeamento de recurso retorne a passagem apropriada, ele deverá acessar o conteúdo remoto do arquivo de manifesto (se diferir do conteúdo local) para ver se há recursos adicionais que precisam ser incluídos. Esses recursos adicionais podem não existir no espaço de trabalho, mas o provedor de repositório saberia como certificar-se de que eles existiam quando a ação selecionada foi executada.

Para oferecer suporte a esses modelos mais complexos, um RemoteResourceMappingContext pode ser transmitido ao método ResourceMapping#getTraversals. Quando um contexto é fornecido, o mapeamento pode utilizá-lo para assegurar-se de que todos os recursos necessários sejam incluídos na passagem. Se um contexto não for fornecido, o mapeamento poderá assumir que apenas o estado local é de interesse.

Quando um ResourceMapping precisa se preocupar com o RemoteResourceMappingContext?

Um ResourceMapping só precisará se preocupar com um contexto fornecido ao método getTraversals nos casos em que os recursos que formam um modelo são alterados além do tempo e o relacionamento entre o modelo e os recursos não pode ser descrito por uma passagem simples que garanta incluir esses recursos (e somente esses recursos) que constituem o modelo. Por exemplo, embora os recursos de um pacote Java possam ser alterados além do tempo, o pacote pode ser descrito como uma pasta da profundidade de um, de modo que um mapeamento de recurso para pacotes java não precisaria utilizar o contexto de mapeamento de recurso.

Como um exemplo mais complexo, considere um arquivo HTML que contém diversas imagens. Suponhamos que todas as referências de imagens de um arquivo HTML façam parte do modelo desse arquivo. Ao atualizar o conteúdo local do arquivo HTML de um repositório, o usuário esperaria que todas as novas imagens fossem incluídas. O método getTraversals de um ResourceMapping para o modelo de arquivo HTML seria semelhante a este:

public class HTMLResourceMapping extends ResourceMapping {
private HTMLFile htmlFile;
public ResourceTraversal[] getTraversals(ResourceMappingContext context,
IProgressMonitor monitor)
IResource[] resources = htmlFile.getResources();
if (context instanceof RemoteResourceMappingContext) {
// Look for any additional resources on the server
RemoteResourceMappingContext remoteContext = (RemoteResourceMappingContext)context;
IFile file = htmlFile.getFile();
if (remoteContext.hasRemoteChange(file, monitor)) {
IStorage storage = remoteContext.fetchRemoteContents(file, monitor);
IResource[] additionalResources = getReferences(storage.getContents());
resources = combine(resources, additionalResources);
}
if (remoteContext.isThreeWay() && remoteContext.hasLocalChange(file, monitor)) {
IStorage storage = remoteContext.fetchBaseContents(file, monitor);
IResource[] additionalResources = getReferences(storage.getContents());
resources = combine(resources, additionalResources);
}
}
return new ResourceTraversal[] {
new ResourceTraversal(resources, IResource.DEPTH_ZERO, IResource.NONE)};
}
}

Observe que há dois conjuntos de recursos incluídos no modelo: aqueles derivados do conteúdo local do arquivo HTML no espaço de trabalho e aqueles obtidos do conteúdo do arquivo remoto e do arquivo base. Em qualquer desses dois conjuntos, pode haver recursos que não existem no espaço de trabalho. Por exemplo, o arquivo HTML local pode conter um link relativo para uma imagem que não existe no espaço de trabalho. Esse recurso deve ser incluído para que ele seja buscado se existir remotamente. Como para o arquivo remoto, ele pode conter uma nova cópia que faz referência a imagens adicionais que deverão ser buscadas quando o novo conteúdo remoto for transferido por download.

Provedores de Modelo

Provedores de modelo são um meio de agrupar mapeamentos de recursos relacionados. Aqui está um link para a classe ModelProvider. Essa classe é útil a três propósitos principais:

  1. Em um provedor de modelo, os clientes podem obter partes adicionais da API para execução de operações em um conjunto de mapeamentos de recurso utilizando o mecanismo adaptável. Por exemplo, o IResourceMappingMerger para o modelo é obtido adaptando o provedor de modelo.
  2. Determinado um conjunto de recursos do sistema de arquivo, os clientes podem consultar se um provedor de modelo tem elementos de modelo permanentes nesses recursos e, caso tenha, obter o conjunto de mapeamentos de recurso que descrevem o relacionamento.
  3. Para operações em um conjunto de recursos, o validador de alteração de recurso consultará os provedores de modelo para determinar se há algum possível efeito colateral de uma operação da qual os usuários deverão estar cientes. Isso é abordado em uma seção separada, em validação de alteração.

Segue o exemplo de uma definição de extensão modelProvider.

   <extension 

id="modelProvider"
name="Library Example"
point="org.eclipse.core.resources.modelProviders">
<modelProvider
class="org.eclipse.team.examples.library.adapt.LibraryModelProvider"
name="Library Example"/>
<extends-model id="org.eclipse.core.resources.modelProvider"/>
<enablement> <test property="org.eclipse.core.resources.projectNature" value="org.eclipse.team.examples.library.view.nature" />
</enablement>
</extension>

O LibraryModelProvider é uma subclasse de ModelProvider. A regra de ativação é utilizada para combinar recursos nos quais o modelo de Biblioteca mantém permanente seu modelo. No exemplo anterior, o provedor de modelo combinará cada recurso em um projeto que tenha natureza de biblioteca.

Uma vez definido o provedor de modelo, o método ResourceMapping#getModelProviderId() deverá ser substituído para retornar o id do provedor de modelo.

   public String getModelProviderId() {
return "org.eclipse.team.examples.library.adapt.modelProvider";
}

Para obter o mapeamento inverso correto dos recursos para o mapeamento daqueles recursos que correspondem à regra de ativação do provedor, substitua também um ou ambos os métodos getMapping. O método a ser substituído depende do modelo ter elementos que contenham vários recursos ou não. Se os elementos de modelo forem mapeados para um único recurso, será possível substituir o método que aceita um único argumento IResource. Caso contrário, você precisará substituir o método que aceita uma matriz de recursos. Aqui está um exemplo utilizando o caso de recurso único.

O método de exemplo a seguir agrupa um arquivo de modelo de biblioteca em um mapeamento de recurso apropriado. Além disso, ele agrupa pastas que contêm arquivos de interesse do provedor de modelo.

public class LibraryModelProvider extends ModelProvider {
public ResourceMapping[] getMappings(IResource resource,
ResourceMappingContext context, IProgressMonitor monitor) {
if (isModelFile(resource)) {
// Return a resource mapping on the file
return new LibraryResourceMapping(resource);
} if (containsModelFiles(resource)) {
// Create a deep resource mapping on the container
return new LibraryContainerResourceMapping(resource);
}
// The resource is not of interest to this model provider
return null;
}
}

Os clientes podem então acessar o provedor de modelo para determinar se os provedores se preocupam com os recursos nos quais estão prestes a operar. A próxima seção descreve a API que será fornecida às operações de equipe que utilizam a API de provedor de modelo para determinar o conjunto completo de mapeamento de recursos nos quais operar quando uma operação de equipe for executada em um conjunto de recursos ou elementos de modelo selecionados.

Validação de Alteração de Recurso

As operações executadas nos recursos deverão ser validadas primeiramente para garantir que o usuário esteja ciente de qualquer efeito colateral possível. Aqui estão as etapas necessárias para validar uma alteração de recurso.

  1. Estabeleça uma descrição da alteração utilizando o IResourceChangeDescriptionFactory. O depósito de informações produz um IResourceDelta que reflete a aparência que o delta de recurso resultante terá depois que a operação for executada.
  2. Valide a alteração utilizando o ResourceChangeValidator. O validador consulta todos os provedores de modelo que registraram um interesse nos recursos afetados. O resultado é um ou mais status contendo o id do modelo de origem e uma descrição do possível efeito colateral da operação sobre o modelo.
  3. Torne o usuário ciente de qualquer efeito colateral possível dos modelos desconhecidos do originador da operação. Por exemplo, se uma refatoração Java tiver recebido um efeito colateral do modelo Java, ela poderá ser ignorada pois a refatoração entende a semântica do modelo Java. Entretanto, se um efeito colateral do modelo de Biblioteca for retornado, ele deverá ser levado ao conhecimento do usuário, porque o Java não tem conhecimento do modelo de Biblioteca.

Mesclagem Baseada em Modelo

Quando um provedor de Equipe estiver tentando uma mesclagem sem periféricos, ele fará o seguinte:

  1. Obtenha os mapeamentos de recurso dos elementos selecionados
  2. Determine os provedores de modelo envolvidos utilizando o método ResourceMapping#getModelProvider().
  3. Expanda o escopo da operação para incluir todos os mapeamentos de recurso necessários.
  4. Estabeleça uma descrição do estado de sincronização entre local e remoto. Essa descrição é fornecida aos modelos por meio da API IMergeContext.
  5. Adapte os provedores de modelo ao IResourceMappingMerger.
  6. Chame o método validateMerge em cada mesclador, transmitindo a descrição de sincronização, para assegurar-se de não haver uma condição que impeça uma tentativa de mesclagem.
  7. Delegue a mesclagem aos mescladores de modelos para executá-la.
  8. Provedores de modelo podem delegar a mesclagem de arquivos individuais novamente ao provedor de Equipe, se quiserem apenas controlar a ordem da mesclagem, ou podem executá-la eles mesmos e sinalizar para o provedor de equipe quando da conclusão.

Conteúdo de Modelo em Visualizações de Operação de Equipe

A exibição dos elementos de modelo no contexto de uma operação de Equipe é possibilitada pela estrutura de Navegador Comum.

As etapas anteriores permitirão aos modelos aparecer nos diálogos utilizados pelas operações de equipe. Há etapas adicionais necessárias para integração em uma visualização de mesclagem.

Visualização de Histórico

Os seguintes aperfeiçoamentos foram feitos na área dos históricos de arquivo e de elemento de modelo:

Navegação Remota

A seguir, o que foi fornecido para suportar navegação remota:

Decorando Elementos de Modelo com Estado de Equipe

Provedores de equipe podem decorar elementos de modelo convertendo seus decoradores leves para trabalhar em mapeamentos de recurso, da mesma maneira que contribuições de objeto são convertidos para trabalhar em mapeamentos de recurso. Entretanto, há um aspecto da decoração de elemento de modelo lógico que é problemático. Se um elemento de modelo não tiver um mapeamento direto para um recurso, ele poderá não receber uma atualização de rótulo quando os recursos subjacentes forem alterados.

Para tratar esse problema, o ITeamStateProvider foi introduzido a fim de dar aos provedores de modelo acesso a alterações de estado que podem afetar decorações de equipe. Além disso, visualizações de modelo podem utilizar um SynchronizationStateTester para determinar quando os rótulos de elementos de modelo lógico precisam ser atualizados. Essa API conta com a interface ITeamStateProvider para determinar quando o estado de equipe do recurso foi alterado e pode ser transmitido a um decorador de equipe como parte de um IDecorationContext.