Services, transações e proxies dinâmicos – parte I

Introdução

No primeiro semestre deste ano cursei uma disciplina na faculdade onde o trabalho final consistia em escrever um software usando apenas Hibernate e JSF. Desenvolvi então um software de gestão de transporte de cargas, que poderia ser comercializado para empresas que fazem uso de uma frota de veículos para realizar transportes rodoviários.

Falando um pouco sobre sua arquitetura, ele dispõe de uma camada de aplicação composta de serviços que são requisitados pela camada de apresentação – nesse caso, pelos managed beans. O código cliente conhece apenas a interface desse serviço, expressa no código abaixo:

interface EntityService<T, ID extends Serializable> {
    void create(Map<String, Object> parameters);
    Collection<T> readAll();
    T read(ID id);
    Collection<T> readByParameters(Map<String, Object> parameters);
    void update(Map<String, Object> parameters);
    void delete(T t);
}

Cada serviço da camada deve ser expresso através de uma interface que estenda EntityService. Por exemplo, o código abaixo corresponde ao serviço de cadastro de veículos.

public interface VeiculoService extends EntityService<Veiculo, String> {
    // Declaram-se aqui outras operações requeridas por esse serviço.
}

A implementação desse serviço deve conter o corpo para todos os métodos declarados nas duas interfaces. Note que a mesma não precisa ser pública.

class VeiculoServiceImpl implements VeiculoService {
    // Fornece implementações para todos os métodos.
}

Há desvantagens nessa abordagem. Nem sempre é conveniente disponibilizar todos os serviços declarados em EntityService para uma determinada entidade. Por exemplo, e se algum requisito do projeto exigisse que não fosse possível alterar veículos? O código abaixo ilustra uma solução possível.

class VeiculoServiceImpl implements VeiculoService {
    // Não é possível alterar veículos.
    public void update(Map<String, Object> parameters) {
        throw new UnsupportedOperationException("Operação não permitida.");
    }
}

Porém, a discussão do que seria melhor ou não não está no escopo desse artigo, embora fosse interessante continuá-la na seção de comentários.

Finalmente, a classe abaixo é usada pela camada de apresentação para requisitar os serviços.

public class ApplicationServiceFactory {
    public static VeiculoService getVeiculoService() {
        return new VeiculoServiceImpl();
    }
}

Contexto transacional

A abordagem acima é interessante, mas as operações de cada serviço não são executadas sob contexto transacional. Isto é, se tivermos uma operação que precise realizar duas ou mais instruções de persistência de dados, uma eventual falha ocorrida em uma dessas instruções não cancela as anteriores. Isso pode acarretar em estado inconsistente dos dados. Precisamos então aplicar uma solução que permita que as operações dos serviços executem sob contexto transacional.

Há várias soluções para o problema:

  • Usar Spring;
  • Escrever um aspecto;
  • Usar o padrão Proxy.

O objetivo deste artigo é explorar o padrão Proxy e a API de proxies dinâmicos do Java para aplicar um contexto transacional para todos os serviços da aplicação. Será o que desenvolveremos na parte 2.

Até lá!

Services, transações e proxies dinâmicos – parte I

4 comentários sobre “Services, transações e proxies dinâmicos – parte I

    1. tnaires disse:

      Olá Alessandro, obrigado pelo comentário.
      Utilizei o Map por 2 motivos:

      1) Quis fazer algo Ruby-like. Em Ruby é comum trabalhar com hashes, e em Java o que mais se assemelha ao hash é a collection Map;
      2) Nesse projeto implementei um managed bean genérico que disponibiliza para seus filhos um Map onde os campos da página são armazenados. Escolhi um Map para esse fim porque a expression language do JSF oferece bom suporte a essa collection. Dessa forma, ficou prático simplesmente passar o Map para os services. Brevemente escreverei um post para apresentar esse managed bean.

  1. Alessandro disse:

    Entendi. Você poderia me passar esse Managed Bean genérico, em pvt, para que eu possa dá uma olhada? Estava pensando em fazer algo similar.

    1. tnaires disse:

      Alessandro, escrevi um novo post para apresentar o managed bean. Fique à vontade para usá-lo e adaptá-lo às suas necessidades. Caso faça alguma melhoria nele, não deixe de avisar!

      Abraço.

Deixe um comentário