Pular para conteúdo

d5-framework-aplicacao

Possui interfaces e classes para o lado de consulta de um agregado:

Projeção

IProjecao

Representa uma projeção somente leitura de um agregado A, normalmente com um subconjunto de seus atributos. Não acrescenta métodos: apenas documenta, pelo parâmetro de tipo, qual agregado a projeção representa.

IProjecao.java
package dev.sauloaraujo.d5.framework.aplicacao;

import dev.sauloaraujo.d5.framework.dominio.IAgregado;

public interface IProjecao<A extends IAgregado<?>> {
}

No tutorial, UnidadeFederativaProjecao implementa IProjecao<UnidadeFederativa>.

Ordenação

IOrdenacao

Marca um enum como uma das propriedades pelas quais uma projeção P pode ser ordenada. Não acrescenta métodos.

IOrdenacao.java
package dev.sauloaraujo.d5.framework.aplicacao;

public interface IOrdenacao<P extends IProjecao<?>> {
}

No tutorial, UnidadeFederativaOrdenacao implementa IOrdenacao<UnidadeFederativaProjecao>.

Consulta

IConsulta

Representa os parâmetros de uma consulta sobre uma projeção: a ordenação O (opcional), se ela é descendente, o índice da página e o tamanho da página.

IConsulta.java
package dev.sauloaraujo.d5.framework.aplicacao;

import java.util.Optional;

public interface IConsulta<O extends Enum<O> & IOrdenacao<?>> {
    Optional<O> getOrdenacao();

    boolean isDescendente();

    int getIndicePagina();

    int getTamanhoPagina();
}

Consulta

Implementação base de IConsulta. O construtor recebe a ordenação, o indicador de ordem descendente, o índice e o tamanho da página, todos Optional. Valida que o índice da página, quando informado, não é negativo, e que o tamanho da página, quando informado, está entre 1 e TAMANHO_PAGINA_MAXIMO (1000), lançando IllegalArgumentException caso contrário; na ausência de ordenação, descendente, índice e tamanho de página, assume, respectivamente, nenhuma ordenação, false, 0 e TAMANHO_PAGINA_PADRAO (10).

No backend, a consulta é instanciada pelo Spring MVC a partir dos parâmetros da requisição, através do construtor da subclasse: o nome de cada parâmetro do construtor é o nome do parâmetro de requisição correspondente. Isso depende de a classe ser compilada com -parameters, o que o spring-boot-starter-parent, herdado através de d5-pai, já configura. Veja AgregadoControladorAbstrato.

Consulta.java
package dev.sauloaraujo.d5.framework.aplicacao.impl;

import java.util.Objects;
import java.util.Optional;

import org.apache.commons.lang3.Validate;

import dev.sauloaraujo.d5.framework.aplicacao.IConsulta;
import dev.sauloaraujo.d5.framework.aplicacao.IOrdenacao;

public class Consulta<O extends Enum<O> & IOrdenacao<?>> implements IConsulta<O> {
    public static final int TAMANHO_PAGINA_PADRAO = 10;
    public static final int TAMANHO_PAGINA_MAXIMO = 1000;

    private final Optional<O> ordenacao;
    private final boolean descendente;
    private final int indicePagina;
    private final int tamanhoPagina;

    public Consulta(Optional<O> ordenacao, Optional<Boolean> descendente, Optional<Integer> indicePagina,
            Optional<Integer> tamanhoPagina) {
        this.ordenacao = Objects.requireNonNull(ordenacao);

        Objects.requireNonNull(descendente);
        this.descendente = descendente.orElse(false);

        Objects.requireNonNull(indicePagina);
        indicePagina.ifPresent(valor -> Validate.isTrue(valor >= 0, "Índice da página deve ser maior ou igual a zero"));
        this.indicePagina = indicePagina.orElse(0);

        Objects.requireNonNull(tamanhoPagina);
        tamanhoPagina.ifPresent(valor -> Validate.isTrue(valor > 0 && valor <= TAMANHO_PAGINA_MAXIMO,
                "Tamanho da página deve estar entre 1 e %d", TAMANHO_PAGINA_MAXIMO));
        this.tamanhoPagina = tamanhoPagina.orElse(TAMANHO_PAGINA_PADRAO);
    }

    @Override
    public Optional<O> getOrdenacao() {
        return ordenacao;
    }

    @Override
    public boolean isDescendente() {
        return descendente;
    }

    @Override
    public int getIndicePagina() {
        return indicePagina;
    }

    @Override
    public int getTamanhoPagina() {
        return tamanhoPagina;
    }
}

No tutorial, UnidadeFederativaConsulta estende Consulta<UnidadeFederativaOrdenacao>, acrescentando os atributos sigla e nome para filtrar a pesquisa.

Resultado da consulta

IConsultaResultado

Representa o resultado de uma consulta: a página de projeções P e o total de projeções que atendem à consulta, desconsiderando a paginação.

IConsultaResultado.java
package dev.sauloaraujo.d5.framework.aplicacao;

import java.util.List;

public interface IConsultaResultado<P extends IProjecao<?>> {
    List<P> getProjecoes();

    long getTotal();
}

ConsultaResultado

Implementação de IConsultaResultado que recebe as projeções e o total diretamente pelo construtor, validando que o total não é negativo. Guarda uma cópia imutável da lista de projeções (List.copyOf), que não admite elementos null.

ConsultaResultado.java
package dev.sauloaraujo.d5.framework.aplicacao.impl;

import java.util.List;
import java.util.Objects;

import org.apache.commons.lang3.Validate;

import dev.sauloaraujo.d5.framework.aplicacao.IConsultaResultado;
import dev.sauloaraujo.d5.framework.aplicacao.IProjecao;

public class ConsultaResultado<P extends IProjecao<?>> implements IConsultaResultado<P> {
    private final List<P> projecoes;
    private final long total;

    public ConsultaResultado(List<P> projecoes, long total) {
        Objects.requireNonNull(projecoes);
        Validate.isTrue(total >= 0);
        this.projecoes = List.copyOf(projecoes);
        this.total = total;
    }

    @Override
    public List<P> getProjecoes() {
        return projecoes;
    }

    @Override
    public long getTotal() {
        return total;
    }
}

Serviço de aplicação

IAgregadoAplicacaoServico

Expõe a operação de pesquisa sobre um agregado: pesquisar, que recebe uma consulta C e devolve um resultado de projeções P.

IAgregadoAplicacaoServico.java
package dev.sauloaraujo.d5.framework.aplicacao;

public interface IAgregadoAplicacaoServico<P extends IProjecao<?>, C extends IConsulta<? extends IOrdenacao<P>>> {
    IConsultaResultado<P> pesquisar(C consulta);
}

Implementações são registradas automaticamente como beans — veja Registro de beans.

AgregadoAplicacaoServicoAbstrato

Implementação base de IAgregadoAplicacaoServico. É parametrizada pelo identificador I, pelo agregado A e pelas autorizações U do serviço correspondente, e pela projeção P e pela consulta C da pesquisa. Recebe no construtor o repositório de aplicação do agregado e o IAgregadoServico correspondente, usado apenas para validar, em pesquisar, se o usuário está autorizado a buscar o agregado — através de getBuscar das autorizações devolvidas por criarAutorizacoes com um identificador vazio — e lançar NaoAutorizadoExcecao caso contrário. A consulta em si é delegada ao repositório de aplicação.

AgregadoAplicacaoServicoAbstrato.java
package dev.sauloaraujo.d5.framework.aplicacao.impl;

import java.util.Objects;
import java.util.Optional;

import dev.sauloaraujo.d5.framework.aplicacao.IAgregadoAplicacaoServico;
import dev.sauloaraujo.d5.framework.aplicacao.IConsulta;
import dev.sauloaraujo.d5.framework.aplicacao.IConsultaResultado;
import dev.sauloaraujo.d5.framework.aplicacao.IOrdenacao;
import dev.sauloaraujo.d5.framework.aplicacao.IProjecao;
import dev.sauloaraujo.d5.framework.aplicacao.spi.IAgregadoAplicacaoRepositorio;
import dev.sauloaraujo.d5.framework.dominio.IAgregado;
import dev.sauloaraujo.d5.framework.dominio.IAgregadoAutorizacoes;
import dev.sauloaraujo.d5.framework.dominio.IAgregadoServico;
import dev.sauloaraujo.d5.framework.dominio.IIdentificador;
import dev.sauloaraujo.d5.framework.dominio.spi.NaoAutorizadoExcecao;

public abstract class AgregadoAplicacaoServicoAbstrato<I extends IIdentificador, A extends IAgregado<I>, U extends IAgregadoAutorizacoes<A>, P extends IProjecao<A>, C extends IConsulta<? extends IOrdenacao<P>>>
        implements IAgregadoAplicacaoServico<P, C> {
    private final IAgregadoAplicacaoRepositorio<P, C> repositorio;
    private final IAgregadoServico<I, A, U> servico;

    protected AgregadoAplicacaoServicoAbstrato(IAgregadoAplicacaoRepositorio<P, C> repositorio,
            IAgregadoServico<I, A, U> servico) {
        this.repositorio = Objects.requireNonNull(repositorio);
        this.servico = Objects.requireNonNull(servico);
    }

    @Override
    public IConsultaResultado<P> pesquisar(C consulta) {
        Objects.requireNonNull(consulta);
        if (!servico.criarAutorizacoes(Optional.empty()).getBuscar()) {
            throw new NaoAutorizadoExcecao("Ação não autorizada");
        }
        return repositorio.pesquisar(consulta);
    }
}

No tutorial, UnidadeFederativaAplicacaoServico estende AgregadoAplicacaoServicoAbstrato.

Repositório de aplicação

IAgregadoAplicacaoRepositorio

Dá acesso, através de pesquisar, às projeções P de um agregado persistidas, filtradas, ordenadas e paginadas conforme uma consulta C.

IAgregadoAplicacaoRepositorio.java
package dev.sauloaraujo.d5.framework.aplicacao.spi;

import dev.sauloaraujo.d5.framework.aplicacao.IConsulta;
import dev.sauloaraujo.d5.framework.aplicacao.IConsultaResultado;
import dev.sauloaraujo.d5.framework.aplicacao.IOrdenacao;
import dev.sauloaraujo.d5.framework.aplicacao.IProjecao;

public interface IAgregadoAplicacaoRepositorio<P extends IProjecao<?>, C extends IConsulta<? extends IOrdenacao<P>>> {
    IConsultaResultado<P> pesquisar(C consulta);
}

Implementações são registradas automaticamente como beans — veja Registro de beans.

No tutorial, IUnidadeFederativaAplicacaoRepositorio estende essa interface. Sua implementação com Spring Data JPA estende AgregadoAplicacaoRepositorioAbstrato, do módulo d5-framework-infraestrutura.