d5-framework-aplicacao
Possui interfaces e classes para o lado de consulta de um agregado:
- projeção;
- ordenação;
- consulta;
- resultado da consulta;
- serviço de aplicação;
- repositório de aplicação.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.