Construtores do Projeto Incremental

Um construtor do projeto incremental é um objeto que manipula os recursos em um projeto na forma que é definido pelo próprio construtor. Os construtores do projeto incremental são freqüentemente utilizados para aplicar uma transformação em um recurso para produzir um recurso ou artifact de outro tipo.

Os plug-ins contribuem com construtores de projeto incremental para a plataforma a fim de implementar transformações de recurso especializado. Por exemplo, o plug-in do Java Development Tooling (JDT) que é fornecido com a plataforma SDK define um construtor de projeto incremental que compila um arquivo de recurso Java em um arquivo de classe em qualquer momento que um arquivo for incluído ou modificado em um projeto Java e compila novamente qualquer outro arquivo afetado por uma alteração.

A plataforma define dois tipos de construção:

As construções incrementais são semeadas com um delta de alteração de recurso. O delta reflete o efeito de rede de todas as alterações de recurso desde que o construtor fez a última construção do projeto. Esse delta é similar ao que é utilizado dentro dos eventos de alteração de recurso.

Os construtores são melhor entendidos pelo exemplo. O Java Development Tooling (JDT) fornece um compilador Java que é levado por um construtor de projeto incremental Java para compilar novamente arquivos que são afetados por alterações. Quando uma construção completa é disparada, todos os arquivos .java no projeto são compilados.  Qualquer problema na compilação é incluído como marcador de problemas nos arquivos .java afetados. Quando uma construção incremental é disparada, o construtor compila novamente de forma seletiva os arquivos .java incluídos, alterados ou de alguma forma afetados que são descritos no delta do recurso e atualiza os marcadores de problemas, se necessário. Qualquer arquivo .class ou marcador que não seja mais apropriado é removido.

As construções incrementais possuem benefícios de desempenho óbvios para projetos com centenas ou milhares de recursos, a maioria deles não podem ser alterados em nenhum ponto dados no tempo.

A objeção técnica para construção incremental é determinar exatamente o que é necessário ser reconstruído. Por exemplo, o estado interno mantido pelo construtor Java inclui coisas como um gráfico de dependência e uma lista de problemas de compilação informados.  Essas informações são utilizadas durante uma construção incremental para identificar quais classes precisam ser compiladas novamente em resposta a uma alteração em um recurso Java.

Apesar de a estrutura básica para construções ser definida na plataforma, o trabalho real é feito no plug-in. Os padrões para a implementação complexa de construtores incrementais estão longe do escopo dessa discussão, desde que a implementação seja dependente do design do construtor específico.

Chamando uma construção

Um construtor pode ser chamado explicitamente de uma das seguintes maneiras:

Na prática, o usuário do workbench dispara uma construção selecionando os comandos correspondentes no menu do navegador de recurso.

Os construtores de projeto incremental são também chamados implicitamente pela plataforma durante a construção automática. Se ativada, as construções automáticas são executadas em qualquer lugar na área de trabalho que é alterada.

Definindo um construtor de projeto incremental

O ponto de extensão org.eclipse.core.resources.builders é utilizado para contribuir com um construtor de projeto incremental para a plataforma. A seguinte marcação mostra como o plug-in hipotético com.example.builders poderia contribuir com o construtor de projeto incremental.

<extension
    point="org.eclipse.core.resources.builders">
    <builder
        id="com.example.builders"
        name="MyBuilder">
        <run 
            class="com.example.builders.BuilderExample">
            <parameter name="optimize" value="true" />
            <parameter name="comment" value="Builder comment" />
        </run>

    </builder>

</extension>

A classe identificada no ponto de extensão aumenta a classe da plataforma IncrementalProjectBuilder.

public class BuilderExample extends IncrementalProjectBuilder {
    IProject[] build(int kind, Map args, IProgressMonitor monitor)
            throws CoreException {
        // inclua aqui sua construção lógica
        return null;
    }
    protected void startupOnInitialize() {
        // inclua aqui o construtor init
    }
}

O processo de construção começa com o método construção(), que inclui informações sobre o tipo de construção que foi solicitada, FULL_BUILD, INCREMENTAL_BUILD, ou AUTO_BUILD. Se uma construção incremental foi solicitada, um delta de recurso é fornecido para descrever as alterações nos recursos do projeto desde a última construção. O fragmento a seguir define mais para frente o método construção() .

protected IProject[] build(int kind, Map args, IProgressMonitor monitor
        throws CoreException {
    if (kind == IncrementalProjectBuilder.FULL_BUILD) {
        fullBuild(monitor);
    } else {
        IResourceDelta delta = getDelta(getProject());
        if (delta == null) {
            fullBuild(monitor);
        } else {
            incrementalBuild(delta, monitor);
        }
    }
    return null;
}

Isso algumas vezes acontece quando o projeto de construção "X," um construtor precisa de informações sobre alterações em algum outro projeto "Y."  (Por exemplo, se uma classe Java em X implementar uma interface fornecida em Y.)  Enquanto construir X, um delta para Y fica disponível para chamar getDelta(Y).  Para garantir que a plataforma possa fornecer esses deltas, o construtor de X deve ter declarado a dependência entre X e Y retornando uma matriz que contenha Y de uma chamada de construção() anterior.  Se um construtor não tiver dependências, é possível simplesmente retornar nulo.  ConsulteIncrementalProjectBuilder para obter mais informações.

Construção completa

A lógica necessária para processar um pedido de construção completa é específico para o plug-in. Isso pode envolver a visita a todos os recursos no projeto (se a construção for disparada para um projeto) ou mesmo o exame de outros projetos se houver dependências entre os projetos.  O seguinte fragmento sugere como uma construção completa pode ser implementada.

protected void fullBuild(final IProgressMonitor monitor) throws CoreException {
    try {
        getProject().accept(new MyBuildVisitor());
    } catch (CoreException e) { }
}

O visitante da construção executaria a construção para o recurso específico (sem resposta verdadeira para continuar visitando todos os recursos filho).

a classe MyBuildVisitor implementa IResourceVisitor {
    public boolean visit(IResource res) {
        //construir o recurso específico.
        //retorno verdadeiro para continuar visitando os filhos.
        retorno verdadeiro;
    }
}

O processo de visitação continua até que a árvore de recurso completa tenha sido movida.

Construção incremental

Quando executar uma construção incremental, você trabalha com um delta de alteração de recurso em vez de todo o projeto.

protected void incrementalBuild(IResourceDelta delta, 
        IProgressMonitor monitor) throws CoreException {
    // o visitante não funciona.
    delta.accept(new MyBuildDeltaVisitor());
}

Observe que para construção incremental, o visitante da construção funciona com uma árvore de delta de recurso em vez de uma árvore completa de recurso.

O processo de visitação continua até que a árvore do delta do recurso completo tenha sido movida. A natureza específica das alterações é similar àquela descrita emImplementando um atendente de alteração de recurso.  Uma diferença importante é que com os construtores de projeto incremental, você está trabalhando normalmente com um delta de recurso com base em um determinado projeto, não na área de trabalho inteira.

Associando um construtor de projeto incremental a um projeto

Para disponibilizar um construtor para um projeto informado, é necessário incluí-lo na construção específica para o projeto. Uma construção específica do projeto é uma lista de comandos para executar, na seqüência, quando o projeto é construído. Cada comando nomeia um construtor de projeto incremental simples.

O fragmento a seguir inclui um novo construtor como o primeiro construtor na lista de construtores existentes.

IProjectDescription desc = project.getDescription();
ICommand[] commands = desc.getBuildSpec();
boolean found = false;

for (int i = 0; i < commands.length; ++i) {
    if (commands[i].getBuilderName().equals(BUILDER_ID)) {
        found = true;
        break;
    }
}
if (!found) { 
    //incluir construtor para o projeto
    ICommand command = desc.newCommand();
    command.setBuilderName(BUILDER_ID);
    ICommand[] newCommands = new ICommand[commands.length + 1];

    // Incluí-lo antes de outros construtores.
    System.arraycopy(commands, 0, newCommands, 1, commands.length);
    newCommands[0] = command;
    desc.setBuildSpec(newCommands);
    project.setDescription(desc, null);
}

A configuração do construtor do projeto é feita somente uma vez, normalmente enquanto o projeto está sendo criado.