Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Dúvidas com Solid + Regras de Negócio

Tenho uma aplicação JSF + JPA que eu dividi em 3 camadas. Os managed beans que interagem com a UI, os repositórios que são a camada de persistência, as classes de entidade que representam o modelo e algumas classes que serviço que tratam das regras de negócio.

A aplicação é uma aplicação de diário oficial, a seguir tenho a classe de serviço do diário, com as seguintes regras de negocio: -Incluir : a data de circulação deve ser única e apenas administradores podem criar diários -Alterar: apenas administradores podem alterar, só pode alterar se o diário ainda estiver aberto e deve garantir que a data de circulação seja única -Fechar: só administradores podem fechar o diário, só pode fechar um diário que esteja aberto e garantir as mesmas condições de "alterar diário"

A classe está assim:

@Stateless
public class DiarioService {

    @EJB
    private DiariosRepository diariosRepository;

    public Diario salvarDiario(Diario diario, Usuario usuario){
        if(!usuario.getRole().equals(Role.ADMINISTRADOR)){
            throw  new RuntimeException("Apenas administradores podem gerar diários");
        }
        diario.setUsuarioCriacao(usuario);
        diario.setNumero(diariosRepository.numeroProximaPublicacao());
        Diario diariocirculacao = diariosRepository.buscarDiarioPorDataCirculacao(diario.getDataCirculacao());
        if(diariocirculacao != null){
            throw  new RuntimeException("Já existe um diário criado com esta data de circulação");
        }
        diariosRepository.salvarDiario(diario);
        return diario;
    }


    public Diario alterarDiario(Diario diario, Usuario usuario){

        if(!usuario.getRole().equals(Role.ADMINISTRADOR)){
            throw  new RuntimeException("Apenas administradores podem editar diários");
        }
        Diario diarioAux = diariosRepository.findByPrimaryKey(diario.getDiarioId());
        if(diarioAux != null && diarioAux.isFechado() ){
                throw  new RuntimeException("Não é possivel editar diários já fechados");
            }
        Diario diariocirculacao = diariosRepository.buscarDiarioPorDataCirculacao(diario.getDataCirculacao());
        if(diariocirculacao != null && !diariocirculacao.equals(diario)){
            throw  new RuntimeException("Já existe um diário criado com esta data de circulação");
        }
        diariosRepository.alterarDiario(diario);
        return diario;
    }


    public Diario fecharDiario(Diario diario, Usuario usuario){

        diario.setDataFechamento(new Date());
        alterarDiario(diario, usuario);
        return diario;
    }

}

e tenho a classe MateriaService com as seguintes regras:

1-só pode incluir matérias em diários abertos 2- só pode alterar matérias em diários abertos, apanas administradores ou o próprio usuário que incluiu a matéria podem edita-lá e se quem editou foi um adminstrador, devo salva-ló como revisor

@Stateless
public class MateriaService {

    @EJB
    private MateriasRepository materiasRepository;
    @EJB
    private DiariosRepository diariosRepository;

    public Materia salvarMateria(Materia materia, Usuario usuario){
        boolean diarioAberto = diariosRepository.diarioEstaAberto(materia.getDiario().getDiarioId());
        if(!diarioAberto){
            throw new RuntimeException("Esta edição do diário já fechou ");
        }
        materia.setMatriculaInclusao(usuario.getMatricula());
        materia.setSetorOrigem(usuario.getSetor());
        materiasRepository.salvarMateria(materia);
        return materia;
    }


    public Materia alterarMateria(Materia materia, Usuario usuario){
        boolean diarioAberto = diariosRepository.diarioEstaAberto(materia.getDiario().getDiarioId());
        if(!diarioAberto){
            throw new RuntimeException("Esta edição do diário já fechou ");
        }
        if(!materia.permiteModificacao(usuario)){
            throw new RuntimeException("Apenas Administradores ou o próprio usuário que criou a matéria pode editar");
        }
        if(usuario.getRole().equals(Role.ADMINISTRADOR)){
            materia.setMatriculaRevisao(usuario.getMatricula());
        }
        materiasRepository.alterarMateria(materia);
        return materia;
    }

}

Oque me incomoda um pouco é ficar passando esse usuário para a classe de serviço e toda hora ficar checando o perfil dele para realizar alguma ação. Este tipo de código deve ficar na classe de serviço mesmo ou deveria estar no ManagedBean?

Outra coisa que eu não sei se é muito bacana é quando eu faço nas classes de serviço

     materia.setMatriculaInclusao(usuario.getMatricula());
        materia.setSetorOrigem(usuario.getSetor());

ou

       diario.setDataFechamento(new Date());

falando em Solid é teóricamente correto eu ter este tipo de código dentro das classes de serviço ou estas devem apanas fazer a orquestração dos objetos?

1 resposta
solução!

Foram boas perguntas. Eh mais facil comecar pela ultima...

Em geral nao eh boa pratica vc ficar modificando o estado de um parametro que foi passado para seu metodo. Vc esta fazendo bastante isso, chamando varios setters no diario.

Em relacao a passar o usuario, nao vejo problema algum. Vc esta garantindo que, independente ta tecnologia web, vc esta protegendo a acao de um usuario com perfil inadequado. Se vc quiser, pode criar uma classe que cuida disso para vc.. vou deixar um exemplo aqui...

public class LiberaPerfil {

     public void libera(Usuario usuario, Perfil perfil, Consumer<Usuario> funcaoComCodigo) {
   if(usuario.getRoles().contains(perfil)){
       funcaoComCodigo.apply(usuario);
   }
}
}

//uso
new LiberaPerfil().libera(usuario,Perfil.ADMIN,(usuario) -> {...})

Usa um pouco do lambda, mas vc isola a verificacao de perfil e so fica utilizando o objeto.