Esta é uma lista do que os provedores de modelos podem fazer para aproveitar as vantagens do suporte de modelo lógico Equipe:
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.
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:
Object getModelObject()
: O objeto modelo do qual o mapeamento se
originou (ou foi adaptado).ResourceTraversal[]
getTraversals(ResourceMappingContext, IProgressMonitor)
: A passagem de recurso
que cobre os recursos que constituem o objeto modelo.ResourceTraversal
contém um conjunto de recursos e um sinalizador de profundidade que indica a
profundidade na qual os recursos na passagem estão associados ao objeto modelo de
origem. As passagens de recurso são fornecidas a um cliente por um mapeamento de
recurso para descrever o conteúdo de um modelo, de tal forma que o cliente (por exemplo,
um provedor de repositório) possa executar suas operações da forma mais eficiente possível. Os
métodos de interesse são:
getResources()
getDepth()
ResourceMappingContext
e do RemoteResourceMappingContext
é um pouco mais complicado e é descrito na seção Contexto de Mapeamento de Recurso.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.
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.
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.
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 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:
IResourceMappingMerger
para o modelo é obtido
adaptando o provedor de modelo.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.
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.
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.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.Quando um provedor de Equipe estiver tentando uma mesclagem sem periféricos, ele fará o seguinte:
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.
Os seguintes aperfeiçoamentos foram feitos na área dos históricos de arquivo e de elemento de modelo:
A seguir, o que foi fornecido para suportar navegação remota:
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
.